1627f7eb2Smrg /* Pass manager for Fortran front end.
2*4c3eb207Smrg Copyright (C) 2010-2020 Free Software Foundation, Inc.
3627f7eb2Smrg Contributed by Thomas König.
4627f7eb2Smrg
5627f7eb2Smrg This file is part of GCC.
6627f7eb2Smrg
7627f7eb2Smrg GCC is free software; you can redistribute it and/or modify it under
8627f7eb2Smrg the terms of the GNU General Public License as published by the Free
9627f7eb2Smrg Software Foundation; either version 3, or (at your option) any later
10627f7eb2Smrg version.
11627f7eb2Smrg
12627f7eb2Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13627f7eb2Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
14627f7eb2Smrg FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15627f7eb2Smrg for more details.
16627f7eb2Smrg
17627f7eb2Smrg You should have received a copy of the GNU General Public License
18627f7eb2Smrg along with GCC; see the file COPYING3. If not see
19627f7eb2Smrg <http://www.gnu.org/licenses/>. */
20627f7eb2Smrg
21627f7eb2Smrg #include "config.h"
22627f7eb2Smrg #include "system.h"
23627f7eb2Smrg #include "coretypes.h"
24627f7eb2Smrg #include "options.h"
25627f7eb2Smrg #include "gfortran.h"
26627f7eb2Smrg #include "dependency.h"
27627f7eb2Smrg #include "constructor.h"
28627f7eb2Smrg #include "intrinsic.h"
29627f7eb2Smrg
30627f7eb2Smrg /* Forward declarations. */
31627f7eb2Smrg
32627f7eb2Smrg static void strip_function_call (gfc_expr *);
33627f7eb2Smrg static void optimize_namespace (gfc_namespace *);
34627f7eb2Smrg static void optimize_assignment (gfc_code *);
35627f7eb2Smrg static bool optimize_op (gfc_expr *);
36627f7eb2Smrg static bool optimize_comparison (gfc_expr *, gfc_intrinsic_op);
37627f7eb2Smrg static bool optimize_trim (gfc_expr *);
38627f7eb2Smrg static bool optimize_lexical_comparison (gfc_expr *);
39627f7eb2Smrg static void optimize_minmaxloc (gfc_expr **);
40627f7eb2Smrg static bool is_empty_string (gfc_expr *e);
41627f7eb2Smrg static void doloop_warn (gfc_namespace *);
42627f7eb2Smrg static int do_intent (gfc_expr **);
43627f7eb2Smrg static int do_subscript (gfc_expr **);
44627f7eb2Smrg static void optimize_reduction (gfc_namespace *);
45627f7eb2Smrg static int callback_reduction (gfc_expr **, int *, void *);
46627f7eb2Smrg static void realloc_strings (gfc_namespace *);
47627f7eb2Smrg static gfc_expr *create_var (gfc_expr *, const char *vname=NULL);
48627f7eb2Smrg static int matmul_to_var_expr (gfc_expr **, int *, void *);
49627f7eb2Smrg static int matmul_to_var_code (gfc_code **, int *, void *);
50627f7eb2Smrg static int inline_matmul_assign (gfc_code **, int *, void *);
51627f7eb2Smrg static gfc_code * create_do_loop (gfc_expr *, gfc_expr *, gfc_expr *,
52627f7eb2Smrg locus *, gfc_namespace *,
53627f7eb2Smrg char *vname=NULL);
54627f7eb2Smrg static gfc_expr* check_conjg_transpose_variable (gfc_expr *, bool *,
55627f7eb2Smrg bool *);
56627f7eb2Smrg static int call_external_blas (gfc_code **, int *, void *);
57627f7eb2Smrg static int matmul_temp_args (gfc_code **, int *,void *data);
58627f7eb2Smrg static int index_interchange (gfc_code **, int*, void *);
59627f7eb2Smrg static bool is_fe_temp (gfc_expr *e);
60627f7eb2Smrg
61627f7eb2Smrg #ifdef CHECKING_P
62627f7eb2Smrg static void check_locus (gfc_namespace *);
63627f7eb2Smrg #endif
64627f7eb2Smrg
65627f7eb2Smrg /* How deep we are inside an argument list. */
66627f7eb2Smrg
67627f7eb2Smrg static int count_arglist;
68627f7eb2Smrg
69627f7eb2Smrg /* Vector of gfc_expr ** we operate on. */
70627f7eb2Smrg
71627f7eb2Smrg static vec<gfc_expr **> expr_array;
72627f7eb2Smrg
73627f7eb2Smrg /* Pointer to the gfc_code we currently work on - to be able to insert
74627f7eb2Smrg a block before the statement. */
75627f7eb2Smrg
76627f7eb2Smrg static gfc_code **current_code;
77627f7eb2Smrg
78627f7eb2Smrg /* Pointer to the block to be inserted, and the statement we are
79627f7eb2Smrg changing within the block. */
80627f7eb2Smrg
81627f7eb2Smrg static gfc_code *inserted_block, **changed_statement;
82627f7eb2Smrg
83627f7eb2Smrg /* The namespace we are currently dealing with. */
84627f7eb2Smrg
85627f7eb2Smrg static gfc_namespace *current_ns;
86627f7eb2Smrg
87627f7eb2Smrg /* If we are within any forall loop. */
88627f7eb2Smrg
89627f7eb2Smrg static int forall_level;
90627f7eb2Smrg
91627f7eb2Smrg /* Keep track of whether we are within an OMP workshare. */
92627f7eb2Smrg
93627f7eb2Smrg static bool in_omp_workshare;
94627f7eb2Smrg
95627f7eb2Smrg /* Keep track of whether we are within an OMP atomic. */
96627f7eb2Smrg
97627f7eb2Smrg static bool in_omp_atomic;
98627f7eb2Smrg
99627f7eb2Smrg /* Keep track of whether we are within a WHERE statement. */
100627f7eb2Smrg
101627f7eb2Smrg static bool in_where;
102627f7eb2Smrg
103627f7eb2Smrg /* Keep track of iterators for array constructors. */
104627f7eb2Smrg
105627f7eb2Smrg static int iterator_level;
106627f7eb2Smrg
107627f7eb2Smrg /* Keep track of DO loop levels. */
108627f7eb2Smrg
109627f7eb2Smrg typedef struct {
110627f7eb2Smrg gfc_code *c;
111627f7eb2Smrg int branch_level;
112627f7eb2Smrg bool seen_goto;
113627f7eb2Smrg } do_t;
114627f7eb2Smrg
115627f7eb2Smrg static vec<do_t> doloop_list;
116627f7eb2Smrg static int doloop_level;
117627f7eb2Smrg
118627f7eb2Smrg /* Keep track of if and select case levels. */
119627f7eb2Smrg
120627f7eb2Smrg static int if_level;
121627f7eb2Smrg static int select_level;
122627f7eb2Smrg
123627f7eb2Smrg /* Vector of gfc_expr * to keep track of DO loops. */
124627f7eb2Smrg
125627f7eb2Smrg struct my_struct *evec;
126627f7eb2Smrg
127627f7eb2Smrg /* Keep track of association lists. */
128627f7eb2Smrg
129627f7eb2Smrg static bool in_assoc_list;
130627f7eb2Smrg
131627f7eb2Smrg /* Counter for temporary variables. */
132627f7eb2Smrg
133627f7eb2Smrg static int var_num = 1;
134627f7eb2Smrg
135627f7eb2Smrg /* What sort of matrix we are dealing with when inlining MATMUL. */
136627f7eb2Smrg
137627f7eb2Smrg enum matrix_case { none=0, A2B2, A2B1, A1B2, A2B2T, A2TB2, A2TB2T };
138627f7eb2Smrg
139627f7eb2Smrg /* Keep track of the number of expressions we have inserted so far
140627f7eb2Smrg using create_var. */
141627f7eb2Smrg
142627f7eb2Smrg int n_vars;
143627f7eb2Smrg
144627f7eb2Smrg /* Entry point - run all passes for a namespace. */
145627f7eb2Smrg
146627f7eb2Smrg void
gfc_run_passes(gfc_namespace * ns)147627f7eb2Smrg gfc_run_passes (gfc_namespace *ns)
148627f7eb2Smrg {
149627f7eb2Smrg
150627f7eb2Smrg /* Warn about dubious DO loops where the index might
151627f7eb2Smrg change. */
152627f7eb2Smrg
153627f7eb2Smrg doloop_level = 0;
154627f7eb2Smrg if_level = 0;
155627f7eb2Smrg select_level = 0;
156627f7eb2Smrg doloop_warn (ns);
157627f7eb2Smrg doloop_list.release ();
158627f7eb2Smrg int w, e;
159627f7eb2Smrg
160627f7eb2Smrg #ifdef CHECKING_P
161627f7eb2Smrg check_locus (ns);
162627f7eb2Smrg #endif
163627f7eb2Smrg
164627f7eb2Smrg gfc_get_errors (&w, &e);
165627f7eb2Smrg if (e > 0)
166627f7eb2Smrg return;
167627f7eb2Smrg
168627f7eb2Smrg if (flag_frontend_optimize || flag_frontend_loop_interchange)
169627f7eb2Smrg optimize_namespace (ns);
170627f7eb2Smrg
171627f7eb2Smrg if (flag_frontend_optimize)
172627f7eb2Smrg {
173627f7eb2Smrg optimize_reduction (ns);
174627f7eb2Smrg if (flag_dump_fortran_optimized)
175627f7eb2Smrg gfc_dump_parse_tree (ns, stdout);
176627f7eb2Smrg
177627f7eb2Smrg expr_array.release ();
178627f7eb2Smrg }
179627f7eb2Smrg
180627f7eb2Smrg if (flag_realloc_lhs)
181627f7eb2Smrg realloc_strings (ns);
182627f7eb2Smrg }
183627f7eb2Smrg
184627f7eb2Smrg #ifdef CHECKING_P
185627f7eb2Smrg
186627f7eb2Smrg /* Callback function: Warn if there is no location information in a
187627f7eb2Smrg statement. */
188627f7eb2Smrg
189627f7eb2Smrg static int
check_locus_code(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)190627f7eb2Smrg check_locus_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
191627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
192627f7eb2Smrg {
193627f7eb2Smrg current_code = c;
194627f7eb2Smrg if (c && *c && (((*c)->loc.nextc == NULL) || ((*c)->loc.lb == NULL)))
195627f7eb2Smrg gfc_warning_internal (0, "Inconsistent internal state: "
196627f7eb2Smrg "No location in statement");
197627f7eb2Smrg
198627f7eb2Smrg return 0;
199627f7eb2Smrg }
200627f7eb2Smrg
201627f7eb2Smrg
202627f7eb2Smrg /* Callback function: Warn if there is no location information in an
203627f7eb2Smrg expression. */
204627f7eb2Smrg
205627f7eb2Smrg static int
check_locus_expr(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)206627f7eb2Smrg check_locus_expr (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
207627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
208627f7eb2Smrg {
209627f7eb2Smrg
210627f7eb2Smrg if (e && *e && (((*e)->where.nextc == NULL || (*e)->where.lb == NULL)))
211627f7eb2Smrg gfc_warning_internal (0, "Inconsistent internal state: "
212627f7eb2Smrg "No location in expression near %L",
213627f7eb2Smrg &((*current_code)->loc));
214627f7eb2Smrg return 0;
215627f7eb2Smrg }
216627f7eb2Smrg
217627f7eb2Smrg /* Run check for missing location information. */
218627f7eb2Smrg
219627f7eb2Smrg static void
check_locus(gfc_namespace * ns)220627f7eb2Smrg check_locus (gfc_namespace *ns)
221627f7eb2Smrg {
222627f7eb2Smrg gfc_code_walker (&ns->code, check_locus_code, check_locus_expr, NULL);
223627f7eb2Smrg
224627f7eb2Smrg for (ns = ns->contained; ns; ns = ns->sibling)
225627f7eb2Smrg {
226627f7eb2Smrg if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
227627f7eb2Smrg check_locus (ns);
228627f7eb2Smrg }
229627f7eb2Smrg }
230627f7eb2Smrg
231627f7eb2Smrg #endif
232627f7eb2Smrg
233627f7eb2Smrg /* Callback for each gfc_code node invoked from check_realloc_strings.
234627f7eb2Smrg For an allocatable LHS string which also appears as a variable on
235627f7eb2Smrg the RHS, replace
236627f7eb2Smrg
237627f7eb2Smrg a = a(x:y)
238627f7eb2Smrg
239627f7eb2Smrg with
240627f7eb2Smrg
241627f7eb2Smrg tmp = a(x:y)
242627f7eb2Smrg a = tmp
243627f7eb2Smrg */
244627f7eb2Smrg
245627f7eb2Smrg static int
realloc_string_callback(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)246627f7eb2Smrg realloc_string_callback (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
247627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
248627f7eb2Smrg {
249627f7eb2Smrg gfc_expr *expr1, *expr2;
250627f7eb2Smrg gfc_code *co = *c;
251627f7eb2Smrg gfc_expr *n;
252627f7eb2Smrg gfc_ref *ref;
253627f7eb2Smrg bool found_substr;
254627f7eb2Smrg
255627f7eb2Smrg if (co->op != EXEC_ASSIGN)
256627f7eb2Smrg return 0;
257627f7eb2Smrg
258627f7eb2Smrg expr1 = co->expr1;
259627f7eb2Smrg if (expr1->ts.type != BT_CHARACTER
260627f7eb2Smrg || !gfc_expr_attr(expr1).allocatable
261627f7eb2Smrg || !expr1->ts.deferred)
262627f7eb2Smrg return 0;
263627f7eb2Smrg
264627f7eb2Smrg if (is_fe_temp (expr1))
265627f7eb2Smrg return 0;
266627f7eb2Smrg
267627f7eb2Smrg expr2 = gfc_discard_nops (co->expr2);
268627f7eb2Smrg
269627f7eb2Smrg if (expr2->expr_type == EXPR_VARIABLE)
270627f7eb2Smrg {
271627f7eb2Smrg found_substr = false;
272627f7eb2Smrg for (ref = expr2->ref; ref; ref = ref->next)
273627f7eb2Smrg {
274627f7eb2Smrg if (ref->type == REF_SUBSTRING)
275627f7eb2Smrg {
276627f7eb2Smrg found_substr = true;
277627f7eb2Smrg break;
278627f7eb2Smrg }
279627f7eb2Smrg }
280627f7eb2Smrg if (!found_substr)
281627f7eb2Smrg return 0;
282627f7eb2Smrg }
283627f7eb2Smrg else if (expr2->expr_type != EXPR_ARRAY
284627f7eb2Smrg && (expr2->expr_type != EXPR_OP
285627f7eb2Smrg || expr2->value.op.op != INTRINSIC_CONCAT))
286627f7eb2Smrg return 0;
287627f7eb2Smrg
288627f7eb2Smrg if (!gfc_check_dependency (expr1, expr2, true))
289627f7eb2Smrg return 0;
290627f7eb2Smrg
291627f7eb2Smrg /* gfc_check_dependency doesn't always pick up identical expressions.
292627f7eb2Smrg However, eliminating the above sends the compiler into an infinite
293627f7eb2Smrg loop on valid expressions. Without this check, the gimplifier emits
294627f7eb2Smrg an ICE for a = a, where a is deferred character length. */
295627f7eb2Smrg if (!gfc_dep_compare_expr (expr1, expr2))
296627f7eb2Smrg return 0;
297627f7eb2Smrg
298627f7eb2Smrg current_code = c;
299627f7eb2Smrg inserted_block = NULL;
300627f7eb2Smrg changed_statement = NULL;
301627f7eb2Smrg n = create_var (expr2, "realloc_string");
302627f7eb2Smrg co->expr2 = n;
303627f7eb2Smrg return 0;
304627f7eb2Smrg }
305627f7eb2Smrg
306627f7eb2Smrg /* Callback for each gfc_code node invoked through gfc_code_walker
307627f7eb2Smrg from optimize_namespace. */
308627f7eb2Smrg
309627f7eb2Smrg static int
optimize_code(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)310627f7eb2Smrg optimize_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
311627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
312627f7eb2Smrg {
313627f7eb2Smrg
314627f7eb2Smrg gfc_exec_op op;
315627f7eb2Smrg
316627f7eb2Smrg op = (*c)->op;
317627f7eb2Smrg
318627f7eb2Smrg if (op == EXEC_CALL || op == EXEC_COMPCALL || op == EXEC_ASSIGN_CALL
319627f7eb2Smrg || op == EXEC_CALL_PPC)
320627f7eb2Smrg count_arglist = 1;
321627f7eb2Smrg else
322627f7eb2Smrg count_arglist = 0;
323627f7eb2Smrg
324627f7eb2Smrg current_code = c;
325627f7eb2Smrg inserted_block = NULL;
326627f7eb2Smrg changed_statement = NULL;
327627f7eb2Smrg
328627f7eb2Smrg if (op == EXEC_ASSIGN)
329627f7eb2Smrg optimize_assignment (*c);
330627f7eb2Smrg return 0;
331627f7eb2Smrg }
332627f7eb2Smrg
333627f7eb2Smrg /* Callback for each gfc_expr node invoked through gfc_code_walker
334627f7eb2Smrg from optimize_namespace. */
335627f7eb2Smrg
336627f7eb2Smrg static int
optimize_expr(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)337627f7eb2Smrg optimize_expr (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
338627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
339627f7eb2Smrg {
340627f7eb2Smrg bool function_expr;
341627f7eb2Smrg
342627f7eb2Smrg if ((*e)->expr_type == EXPR_FUNCTION)
343627f7eb2Smrg {
344627f7eb2Smrg count_arglist ++;
345627f7eb2Smrg function_expr = true;
346627f7eb2Smrg }
347627f7eb2Smrg else
348627f7eb2Smrg function_expr = false;
349627f7eb2Smrg
350627f7eb2Smrg if (optimize_trim (*e))
351627f7eb2Smrg gfc_simplify_expr (*e, 0);
352627f7eb2Smrg
353627f7eb2Smrg if (optimize_lexical_comparison (*e))
354627f7eb2Smrg gfc_simplify_expr (*e, 0);
355627f7eb2Smrg
356627f7eb2Smrg if ((*e)->expr_type == EXPR_OP && optimize_op (*e))
357627f7eb2Smrg gfc_simplify_expr (*e, 0);
358627f7eb2Smrg
359627f7eb2Smrg if ((*e)->expr_type == EXPR_FUNCTION && (*e)->value.function.isym)
360627f7eb2Smrg switch ((*e)->value.function.isym->id)
361627f7eb2Smrg {
362627f7eb2Smrg case GFC_ISYM_MINLOC:
363627f7eb2Smrg case GFC_ISYM_MAXLOC:
364627f7eb2Smrg optimize_minmaxloc (e);
365627f7eb2Smrg break;
366627f7eb2Smrg default:
367627f7eb2Smrg break;
368627f7eb2Smrg }
369627f7eb2Smrg
370627f7eb2Smrg if (function_expr)
371627f7eb2Smrg count_arglist --;
372627f7eb2Smrg
373627f7eb2Smrg return 0;
374627f7eb2Smrg }
375627f7eb2Smrg
376627f7eb2Smrg /* Auxiliary function to handle the arguments to reduction intrnisics. If the
377627f7eb2Smrg function is a scalar, just copy it; otherwise returns the new element, the
378627f7eb2Smrg old one can be freed. */
379627f7eb2Smrg
380627f7eb2Smrg static gfc_expr *
copy_walk_reduction_arg(gfc_constructor * c,gfc_expr * fn)381627f7eb2Smrg copy_walk_reduction_arg (gfc_constructor *c, gfc_expr *fn)
382627f7eb2Smrg {
383627f7eb2Smrg gfc_expr *fcn, *e = c->expr;
384627f7eb2Smrg
385627f7eb2Smrg fcn = gfc_copy_expr (e);
386627f7eb2Smrg if (c->iterator)
387627f7eb2Smrg {
388627f7eb2Smrg gfc_constructor_base newbase;
389627f7eb2Smrg gfc_expr *new_expr;
390627f7eb2Smrg gfc_constructor *new_c;
391627f7eb2Smrg
392627f7eb2Smrg newbase = NULL;
393627f7eb2Smrg new_expr = gfc_get_expr ();
394627f7eb2Smrg new_expr->expr_type = EXPR_ARRAY;
395627f7eb2Smrg new_expr->ts = e->ts;
396627f7eb2Smrg new_expr->where = e->where;
397627f7eb2Smrg new_expr->rank = 1;
398627f7eb2Smrg new_c = gfc_constructor_append_expr (&newbase, fcn, &(e->where));
399627f7eb2Smrg new_c->iterator = c->iterator;
400627f7eb2Smrg new_expr->value.constructor = newbase;
401627f7eb2Smrg c->iterator = NULL;
402627f7eb2Smrg
403627f7eb2Smrg fcn = new_expr;
404627f7eb2Smrg }
405627f7eb2Smrg
406627f7eb2Smrg if (fcn->rank != 0)
407627f7eb2Smrg {
408627f7eb2Smrg gfc_isym_id id = fn->value.function.isym->id;
409627f7eb2Smrg
410627f7eb2Smrg if (id == GFC_ISYM_SUM || id == GFC_ISYM_PRODUCT)
411627f7eb2Smrg fcn = gfc_build_intrinsic_call (current_ns, id,
412627f7eb2Smrg fn->value.function.isym->name,
413627f7eb2Smrg fn->where, 3, fcn, NULL, NULL);
414627f7eb2Smrg else if (id == GFC_ISYM_ANY || id == GFC_ISYM_ALL)
415627f7eb2Smrg fcn = gfc_build_intrinsic_call (current_ns, id,
416627f7eb2Smrg fn->value.function.isym->name,
417627f7eb2Smrg fn->where, 2, fcn, NULL);
418627f7eb2Smrg else
419627f7eb2Smrg gfc_internal_error ("Illegal id in copy_walk_reduction_arg");
420627f7eb2Smrg
421627f7eb2Smrg fcn->symtree->n.sym->attr.access = ACCESS_PRIVATE;
422627f7eb2Smrg }
423627f7eb2Smrg
424627f7eb2Smrg return fcn;
425627f7eb2Smrg }
426627f7eb2Smrg
427627f7eb2Smrg /* Callback function for optimzation of reductions to scalars. Transform ANY
428627f7eb2Smrg ([f1,f2,f3, ...]) to f1 .or. f2 .or. f3 .or. ..., with ANY, SUM and PRODUCT
429627f7eb2Smrg correspondingly. Handly only the simple cases without MASK and DIM. */
430627f7eb2Smrg
431627f7eb2Smrg static int
callback_reduction(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)432627f7eb2Smrg callback_reduction (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
433627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
434627f7eb2Smrg {
435627f7eb2Smrg gfc_expr *fn, *arg;
436627f7eb2Smrg gfc_intrinsic_op op;
437627f7eb2Smrg gfc_isym_id id;
438627f7eb2Smrg gfc_actual_arglist *a;
439627f7eb2Smrg gfc_actual_arglist *dim;
440627f7eb2Smrg gfc_constructor *c;
441627f7eb2Smrg gfc_expr *res, *new_expr;
442627f7eb2Smrg gfc_actual_arglist *mask;
443627f7eb2Smrg
444627f7eb2Smrg fn = *e;
445627f7eb2Smrg
446627f7eb2Smrg if (fn->rank != 0 || fn->expr_type != EXPR_FUNCTION
447627f7eb2Smrg || fn->value.function.isym == NULL)
448627f7eb2Smrg return 0;
449627f7eb2Smrg
450627f7eb2Smrg id = fn->value.function.isym->id;
451627f7eb2Smrg
452627f7eb2Smrg if (id != GFC_ISYM_SUM && id != GFC_ISYM_PRODUCT
453627f7eb2Smrg && id != GFC_ISYM_ANY && id != GFC_ISYM_ALL)
454627f7eb2Smrg return 0;
455627f7eb2Smrg
456627f7eb2Smrg a = fn->value.function.actual;
457627f7eb2Smrg
458627f7eb2Smrg /* Don't handle MASK or DIM. */
459627f7eb2Smrg
460627f7eb2Smrg dim = a->next;
461627f7eb2Smrg
462627f7eb2Smrg if (dim->expr != NULL)
463627f7eb2Smrg return 0;
464627f7eb2Smrg
465627f7eb2Smrg if (id == GFC_ISYM_SUM || id == GFC_ISYM_PRODUCT)
466627f7eb2Smrg {
467627f7eb2Smrg mask = dim->next;
468627f7eb2Smrg if ( mask->expr != NULL)
469627f7eb2Smrg return 0;
470627f7eb2Smrg }
471627f7eb2Smrg
472627f7eb2Smrg arg = a->expr;
473627f7eb2Smrg
474627f7eb2Smrg if (arg->expr_type != EXPR_ARRAY)
475627f7eb2Smrg return 0;
476627f7eb2Smrg
477627f7eb2Smrg switch (id)
478627f7eb2Smrg {
479627f7eb2Smrg case GFC_ISYM_SUM:
480627f7eb2Smrg op = INTRINSIC_PLUS;
481627f7eb2Smrg break;
482627f7eb2Smrg
483627f7eb2Smrg case GFC_ISYM_PRODUCT:
484627f7eb2Smrg op = INTRINSIC_TIMES;
485627f7eb2Smrg break;
486627f7eb2Smrg
487627f7eb2Smrg case GFC_ISYM_ANY:
488627f7eb2Smrg op = INTRINSIC_OR;
489627f7eb2Smrg break;
490627f7eb2Smrg
491627f7eb2Smrg case GFC_ISYM_ALL:
492627f7eb2Smrg op = INTRINSIC_AND;
493627f7eb2Smrg break;
494627f7eb2Smrg
495627f7eb2Smrg default:
496627f7eb2Smrg return 0;
497627f7eb2Smrg }
498627f7eb2Smrg
499627f7eb2Smrg c = gfc_constructor_first (arg->value.constructor);
500627f7eb2Smrg
501627f7eb2Smrg /* Don't do any simplififcation if we have
502627f7eb2Smrg - no element in the constructor or
503627f7eb2Smrg - only have a single element in the array which contains an
504627f7eb2Smrg iterator. */
505627f7eb2Smrg
506627f7eb2Smrg if (c == NULL)
507627f7eb2Smrg return 0;
508627f7eb2Smrg
509627f7eb2Smrg res = copy_walk_reduction_arg (c, fn);
510627f7eb2Smrg
511627f7eb2Smrg c = gfc_constructor_next (c);
512627f7eb2Smrg while (c)
513627f7eb2Smrg {
514627f7eb2Smrg new_expr = gfc_get_expr ();
515627f7eb2Smrg new_expr->ts = fn->ts;
516627f7eb2Smrg new_expr->expr_type = EXPR_OP;
517627f7eb2Smrg new_expr->rank = fn->rank;
518627f7eb2Smrg new_expr->where = fn->where;
519627f7eb2Smrg new_expr->value.op.op = op;
520627f7eb2Smrg new_expr->value.op.op1 = res;
521627f7eb2Smrg new_expr->value.op.op2 = copy_walk_reduction_arg (c, fn);
522627f7eb2Smrg res = new_expr;
523627f7eb2Smrg c = gfc_constructor_next (c);
524627f7eb2Smrg }
525627f7eb2Smrg
526627f7eb2Smrg gfc_simplify_expr (res, 0);
527627f7eb2Smrg *e = res;
528627f7eb2Smrg gfc_free_expr (fn);
529627f7eb2Smrg
530627f7eb2Smrg return 0;
531627f7eb2Smrg }
532627f7eb2Smrg
533627f7eb2Smrg /* Callback function for common function elimination, called from cfe_expr_0.
534627f7eb2Smrg Put all eligible function expressions into expr_array. */
535627f7eb2Smrg
536627f7eb2Smrg static int
cfe_register_funcs(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)537627f7eb2Smrg cfe_register_funcs (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
538627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
539627f7eb2Smrg {
540627f7eb2Smrg
541627f7eb2Smrg if ((*e)->expr_type != EXPR_FUNCTION)
542627f7eb2Smrg return 0;
543627f7eb2Smrg
544627f7eb2Smrg /* We don't do character functions with unknown charlens. */
545627f7eb2Smrg if ((*e)->ts.type == BT_CHARACTER
546627f7eb2Smrg && ((*e)->ts.u.cl == NULL || (*e)->ts.u.cl->length == NULL
547627f7eb2Smrg || (*e)->ts.u.cl->length->expr_type != EXPR_CONSTANT))
548627f7eb2Smrg return 0;
549627f7eb2Smrg
550627f7eb2Smrg /* We don't do function elimination within FORALL statements, it can
551627f7eb2Smrg lead to wrong-code in certain circumstances. */
552627f7eb2Smrg
553627f7eb2Smrg if (forall_level > 0)
554627f7eb2Smrg return 0;
555627f7eb2Smrg
556627f7eb2Smrg /* Function elimination inside an iterator could lead to functions which
557627f7eb2Smrg depend on iterator variables being moved outside. FIXME: We should check
558627f7eb2Smrg if the functions do indeed depend on the iterator variable. */
559627f7eb2Smrg
560627f7eb2Smrg if (iterator_level > 0)
561627f7eb2Smrg return 0;
562627f7eb2Smrg
563627f7eb2Smrg /* If we don't know the shape at compile time, we create an allocatable
564627f7eb2Smrg temporary variable to hold the intermediate result, but only if
565627f7eb2Smrg allocation on assignment is active. */
566627f7eb2Smrg
567627f7eb2Smrg if ((*e)->rank > 0 && (*e)->shape == NULL && !flag_realloc_lhs)
568627f7eb2Smrg return 0;
569627f7eb2Smrg
570627f7eb2Smrg /* Skip the test for pure functions if -faggressive-function-elimination
571627f7eb2Smrg is specified. */
572627f7eb2Smrg if ((*e)->value.function.esym)
573627f7eb2Smrg {
574627f7eb2Smrg /* Don't create an array temporary for elemental functions. */
575627f7eb2Smrg if ((*e)->value.function.esym->attr.elemental && (*e)->rank > 0)
576627f7eb2Smrg return 0;
577627f7eb2Smrg
578627f7eb2Smrg /* Only eliminate potentially impure functions if the
579627f7eb2Smrg user specifically requested it. */
580627f7eb2Smrg if (!flag_aggressive_function_elimination
581627f7eb2Smrg && !(*e)->value.function.esym->attr.pure
582627f7eb2Smrg && !(*e)->value.function.esym->attr.implicit_pure)
583627f7eb2Smrg return 0;
584627f7eb2Smrg }
585627f7eb2Smrg
586627f7eb2Smrg if ((*e)->value.function.isym)
587627f7eb2Smrg {
588627f7eb2Smrg /* Conversions are handled on the fly by the middle end,
589627f7eb2Smrg transpose during trans-* stages and TRANSFER by the middle end. */
590627f7eb2Smrg if ((*e)->value.function.isym->id == GFC_ISYM_CONVERSION
591627f7eb2Smrg || (*e)->value.function.isym->id == GFC_ISYM_TRANSFER
592627f7eb2Smrg || gfc_inline_intrinsic_function_p (*e))
593627f7eb2Smrg return 0;
594627f7eb2Smrg
595627f7eb2Smrg /* Don't create an array temporary for elemental functions,
596627f7eb2Smrg as this would be wasteful of memory.
597627f7eb2Smrg FIXME: Create a scalar temporary during scalarization. */
598627f7eb2Smrg if ((*e)->value.function.isym->elemental && (*e)->rank > 0)
599627f7eb2Smrg return 0;
600627f7eb2Smrg
601627f7eb2Smrg if (!(*e)->value.function.isym->pure)
602627f7eb2Smrg return 0;
603627f7eb2Smrg }
604627f7eb2Smrg
605627f7eb2Smrg expr_array.safe_push (e);
606627f7eb2Smrg return 0;
607627f7eb2Smrg }
608627f7eb2Smrg
609627f7eb2Smrg /* Auxiliary function to check if an expression is a temporary created by
610627f7eb2Smrg create var. */
611627f7eb2Smrg
612627f7eb2Smrg static bool
is_fe_temp(gfc_expr * e)613627f7eb2Smrg is_fe_temp (gfc_expr *e)
614627f7eb2Smrg {
615627f7eb2Smrg if (e->expr_type != EXPR_VARIABLE)
616627f7eb2Smrg return false;
617627f7eb2Smrg
618627f7eb2Smrg return e->symtree->n.sym->attr.fe_temp;
619627f7eb2Smrg }
620627f7eb2Smrg
621627f7eb2Smrg /* Determine the length of a string, if it can be evaluated as a constant
622627f7eb2Smrg expression. Return a newly allocated gfc_expr or NULL on failure.
623627f7eb2Smrg If the user specified a substring which is potentially longer than
624627f7eb2Smrg the string itself, the string will be padded with spaces, which
625627f7eb2Smrg is harmless. */
626627f7eb2Smrg
627627f7eb2Smrg static gfc_expr *
constant_string_length(gfc_expr * e)628627f7eb2Smrg constant_string_length (gfc_expr *e)
629627f7eb2Smrg {
630627f7eb2Smrg
631627f7eb2Smrg gfc_expr *length;
632627f7eb2Smrg gfc_ref *ref;
633627f7eb2Smrg gfc_expr *res;
634627f7eb2Smrg mpz_t value;
635627f7eb2Smrg
636627f7eb2Smrg if (e->ts.u.cl)
637627f7eb2Smrg {
638627f7eb2Smrg length = e->ts.u.cl->length;
639627f7eb2Smrg if (length && length->expr_type == EXPR_CONSTANT)
640627f7eb2Smrg return gfc_copy_expr(length);
641627f7eb2Smrg }
642627f7eb2Smrg
643627f7eb2Smrg /* See if there is a substring. If it has a constant length, return
644627f7eb2Smrg that and NULL otherwise. */
645627f7eb2Smrg for (ref = e->ref; ref; ref = ref->next)
646627f7eb2Smrg {
647627f7eb2Smrg if (ref->type == REF_SUBSTRING)
648627f7eb2Smrg {
649627f7eb2Smrg if (gfc_dep_difference (ref->u.ss.end, ref->u.ss.start, &value))
650627f7eb2Smrg {
651627f7eb2Smrg res = gfc_get_constant_expr (BT_INTEGER, gfc_charlen_int_kind,
652627f7eb2Smrg &e->where);
653627f7eb2Smrg
654627f7eb2Smrg mpz_add_ui (res->value.integer, value, 1);
655627f7eb2Smrg mpz_clear (value);
656627f7eb2Smrg return res;
657627f7eb2Smrg }
658627f7eb2Smrg else
659627f7eb2Smrg return NULL;
660627f7eb2Smrg }
661627f7eb2Smrg }
662627f7eb2Smrg
663627f7eb2Smrg /* Return length of char symbol, if constant. */
664627f7eb2Smrg if (e->symtree && e->symtree->n.sym->ts.u.cl
665627f7eb2Smrg && e->symtree->n.sym->ts.u.cl->length
666627f7eb2Smrg && e->symtree->n.sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
667627f7eb2Smrg return gfc_copy_expr (e->symtree->n.sym->ts.u.cl->length);
668627f7eb2Smrg
669627f7eb2Smrg return NULL;
670627f7eb2Smrg
671627f7eb2Smrg }
672627f7eb2Smrg
673627f7eb2Smrg /* Insert a block at the current position unless it has already
674627f7eb2Smrg been inserted; in this case use the one already there. */
675627f7eb2Smrg
676627f7eb2Smrg static gfc_namespace*
insert_block()677627f7eb2Smrg insert_block ()
678627f7eb2Smrg {
679627f7eb2Smrg gfc_namespace *ns;
680627f7eb2Smrg
681627f7eb2Smrg /* If the block hasn't already been created, do so. */
682627f7eb2Smrg if (inserted_block == NULL)
683627f7eb2Smrg {
684627f7eb2Smrg inserted_block = XCNEW (gfc_code);
685627f7eb2Smrg inserted_block->op = EXEC_BLOCK;
686627f7eb2Smrg inserted_block->loc = (*current_code)->loc;
687627f7eb2Smrg ns = gfc_build_block_ns (current_ns);
688627f7eb2Smrg inserted_block->ext.block.ns = ns;
689627f7eb2Smrg inserted_block->ext.block.assoc = NULL;
690627f7eb2Smrg
691627f7eb2Smrg ns->code = *current_code;
692627f7eb2Smrg
693627f7eb2Smrg /* If the statement has a label, make sure it is transferred to
694627f7eb2Smrg the newly created block. */
695627f7eb2Smrg
696627f7eb2Smrg if ((*current_code)->here)
697627f7eb2Smrg {
698627f7eb2Smrg inserted_block->here = (*current_code)->here;
699627f7eb2Smrg (*current_code)->here = NULL;
700627f7eb2Smrg }
701627f7eb2Smrg
702627f7eb2Smrg inserted_block->next = (*current_code)->next;
703627f7eb2Smrg changed_statement = &(inserted_block->ext.block.ns->code);
704627f7eb2Smrg (*current_code)->next = NULL;
705627f7eb2Smrg /* Insert the BLOCK at the right position. */
706627f7eb2Smrg *current_code = inserted_block;
707627f7eb2Smrg ns->parent = current_ns;
708627f7eb2Smrg }
709627f7eb2Smrg else
710627f7eb2Smrg ns = inserted_block->ext.block.ns;
711627f7eb2Smrg
712627f7eb2Smrg return ns;
713627f7eb2Smrg }
714627f7eb2Smrg
715627f7eb2Smrg
716627f7eb2Smrg /* Insert a call to the intrinsic len. Use a different name for
717627f7eb2Smrg the symbol tree so we don't run into trouble when the user has
718627f7eb2Smrg renamed len for some reason. */
719627f7eb2Smrg
720627f7eb2Smrg static gfc_expr*
get_len_call(gfc_expr * str)721627f7eb2Smrg get_len_call (gfc_expr *str)
722627f7eb2Smrg {
723627f7eb2Smrg gfc_expr *fcn;
724627f7eb2Smrg gfc_actual_arglist *actual_arglist;
725627f7eb2Smrg
726627f7eb2Smrg fcn = gfc_get_expr ();
727627f7eb2Smrg fcn->expr_type = EXPR_FUNCTION;
728627f7eb2Smrg fcn->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_LEN);
729627f7eb2Smrg actual_arglist = gfc_get_actual_arglist ();
730627f7eb2Smrg actual_arglist->expr = str;
731627f7eb2Smrg
732627f7eb2Smrg fcn->value.function.actual = actual_arglist;
733627f7eb2Smrg fcn->where = str->where;
734627f7eb2Smrg fcn->ts.type = BT_INTEGER;
735627f7eb2Smrg fcn->ts.kind = gfc_charlen_int_kind;
736627f7eb2Smrg
737627f7eb2Smrg gfc_get_sym_tree ("__internal_len", current_ns, &fcn->symtree, false);
738627f7eb2Smrg fcn->symtree->n.sym->ts = fcn->ts;
739627f7eb2Smrg fcn->symtree->n.sym->attr.flavor = FL_PROCEDURE;
740627f7eb2Smrg fcn->symtree->n.sym->attr.function = 1;
741627f7eb2Smrg fcn->symtree->n.sym->attr.elemental = 1;
742627f7eb2Smrg fcn->symtree->n.sym->attr.referenced = 1;
743627f7eb2Smrg fcn->symtree->n.sym->attr.access = ACCESS_PRIVATE;
744627f7eb2Smrg gfc_commit_symbol (fcn->symtree->n.sym);
745627f7eb2Smrg
746627f7eb2Smrg return fcn;
747627f7eb2Smrg }
748627f7eb2Smrg
749627f7eb2Smrg
750627f7eb2Smrg /* Returns a new expression (a variable) to be used in place of the old one,
751627f7eb2Smrg with an optional assignment statement before the current statement to set
752627f7eb2Smrg the value of the variable. Creates a new BLOCK for the statement if that
753627f7eb2Smrg hasn't already been done and puts the statement, plus the newly created
754627f7eb2Smrg variables, in that block. Special cases: If the expression is constant or
755627f7eb2Smrg a temporary which has already been created, just copy it. */
756627f7eb2Smrg
757627f7eb2Smrg static gfc_expr*
create_var(gfc_expr * e,const char * vname)758627f7eb2Smrg create_var (gfc_expr * e, const char *vname)
759627f7eb2Smrg {
760627f7eb2Smrg char name[GFC_MAX_SYMBOL_LEN +1];
761627f7eb2Smrg gfc_symtree *symtree;
762627f7eb2Smrg gfc_symbol *symbol;
763627f7eb2Smrg gfc_expr *result;
764627f7eb2Smrg gfc_code *n;
765627f7eb2Smrg gfc_namespace *ns;
766627f7eb2Smrg int i;
767627f7eb2Smrg bool deferred;
768627f7eb2Smrg
769627f7eb2Smrg if (e->expr_type == EXPR_CONSTANT || is_fe_temp (e))
770627f7eb2Smrg return gfc_copy_expr (e);
771627f7eb2Smrg
772627f7eb2Smrg /* Creation of an array of unknown size requires realloc on assignment.
773627f7eb2Smrg If that is not possible, just return NULL. */
774627f7eb2Smrg if (flag_realloc_lhs == 0 && e->rank > 0 && e->shape == NULL)
775627f7eb2Smrg return NULL;
776627f7eb2Smrg
777627f7eb2Smrg ns = insert_block ();
778627f7eb2Smrg
779627f7eb2Smrg if (vname)
780627f7eb2Smrg snprintf (name, GFC_MAX_SYMBOL_LEN, "__var_%d_%s", var_num++, vname);
781627f7eb2Smrg else
782627f7eb2Smrg snprintf (name, GFC_MAX_SYMBOL_LEN, "__var_%d", var_num++);
783627f7eb2Smrg
784627f7eb2Smrg if (gfc_get_sym_tree (name, ns, &symtree, false) != 0)
785627f7eb2Smrg gcc_unreachable ();
786627f7eb2Smrg
787627f7eb2Smrg symbol = symtree->n.sym;
788627f7eb2Smrg symbol->ts = e->ts;
789627f7eb2Smrg
790627f7eb2Smrg if (e->rank > 0)
791627f7eb2Smrg {
792627f7eb2Smrg symbol->as = gfc_get_array_spec ();
793627f7eb2Smrg symbol->as->rank = e->rank;
794627f7eb2Smrg
795627f7eb2Smrg if (e->shape == NULL)
796627f7eb2Smrg {
797627f7eb2Smrg /* We don't know the shape at compile time, so we use an
798627f7eb2Smrg allocatable. */
799627f7eb2Smrg symbol->as->type = AS_DEFERRED;
800627f7eb2Smrg symbol->attr.allocatable = 1;
801627f7eb2Smrg }
802627f7eb2Smrg else
803627f7eb2Smrg {
804627f7eb2Smrg symbol->as->type = AS_EXPLICIT;
805627f7eb2Smrg /* Copy the shape. */
806627f7eb2Smrg for (i=0; i<e->rank; i++)
807627f7eb2Smrg {
808627f7eb2Smrg gfc_expr *p, *q;
809627f7eb2Smrg
810627f7eb2Smrg p = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
811627f7eb2Smrg &(e->where));
812627f7eb2Smrg mpz_set_si (p->value.integer, 1);
813627f7eb2Smrg symbol->as->lower[i] = p;
814627f7eb2Smrg
815627f7eb2Smrg q = gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind,
816627f7eb2Smrg &(e->where));
817627f7eb2Smrg mpz_set (q->value.integer, e->shape[i]);
818627f7eb2Smrg symbol->as->upper[i] = q;
819627f7eb2Smrg }
820627f7eb2Smrg }
821627f7eb2Smrg }
822627f7eb2Smrg
823627f7eb2Smrg deferred = 0;
824627f7eb2Smrg if (e->ts.type == BT_CHARACTER)
825627f7eb2Smrg {
826627f7eb2Smrg gfc_expr *length;
827627f7eb2Smrg
828627f7eb2Smrg symbol->ts.u.cl = gfc_new_charlen (ns, NULL);
829627f7eb2Smrg length = constant_string_length (e);
830627f7eb2Smrg if (length)
831627f7eb2Smrg symbol->ts.u.cl->length = length;
832627f7eb2Smrg else if (e->expr_type == EXPR_VARIABLE
833627f7eb2Smrg && e->symtree->n.sym->ts.type == BT_CHARACTER
834627f7eb2Smrg && e->ts.u.cl->length)
835627f7eb2Smrg symbol->ts.u.cl->length = get_len_call (gfc_copy_expr (e));
836627f7eb2Smrg else
837627f7eb2Smrg {
838627f7eb2Smrg symbol->attr.allocatable = 1;
839627f7eb2Smrg symbol->ts.u.cl->length = NULL;
840627f7eb2Smrg symbol->ts.deferred = 1;
841627f7eb2Smrg deferred = 1;
842627f7eb2Smrg }
843627f7eb2Smrg }
844627f7eb2Smrg
845627f7eb2Smrg symbol->attr.flavor = FL_VARIABLE;
846627f7eb2Smrg symbol->attr.referenced = 1;
847627f7eb2Smrg symbol->attr.dimension = e->rank > 0;
848627f7eb2Smrg symbol->attr.fe_temp = 1;
849627f7eb2Smrg gfc_commit_symbol (symbol);
850627f7eb2Smrg
851627f7eb2Smrg result = gfc_get_expr ();
852627f7eb2Smrg result->expr_type = EXPR_VARIABLE;
853627f7eb2Smrg result->ts = symbol->ts;
854627f7eb2Smrg result->ts.deferred = deferred;
855627f7eb2Smrg result->rank = e->rank;
856627f7eb2Smrg result->shape = gfc_copy_shape (e->shape, e->rank);
857627f7eb2Smrg result->symtree = symtree;
858627f7eb2Smrg result->where = e->where;
859627f7eb2Smrg if (e->rank > 0)
860627f7eb2Smrg {
861627f7eb2Smrg result->ref = gfc_get_ref ();
862627f7eb2Smrg result->ref->type = REF_ARRAY;
863627f7eb2Smrg result->ref->u.ar.type = AR_FULL;
864627f7eb2Smrg result->ref->u.ar.where = e->where;
865627f7eb2Smrg result->ref->u.ar.dimen = e->rank;
866627f7eb2Smrg result->ref->u.ar.as = symbol->ts.type == BT_CLASS
867627f7eb2Smrg ? CLASS_DATA (symbol)->as : symbol->as;
868627f7eb2Smrg if (warn_array_temporaries)
869627f7eb2Smrg gfc_warning (OPT_Warray_temporaries,
870627f7eb2Smrg "Creating array temporary at %L", &(e->where));
871627f7eb2Smrg }
872627f7eb2Smrg
873627f7eb2Smrg /* Generate the new assignment. */
874627f7eb2Smrg n = XCNEW (gfc_code);
875627f7eb2Smrg n->op = EXEC_ASSIGN;
876627f7eb2Smrg n->loc = (*current_code)->loc;
877627f7eb2Smrg n->next = *changed_statement;
878627f7eb2Smrg n->expr1 = gfc_copy_expr (result);
879627f7eb2Smrg n->expr2 = e;
880627f7eb2Smrg *changed_statement = n;
881627f7eb2Smrg n_vars ++;
882627f7eb2Smrg
883627f7eb2Smrg return result;
884627f7eb2Smrg }
885627f7eb2Smrg
886627f7eb2Smrg /* Warn about function elimination. */
887627f7eb2Smrg
888627f7eb2Smrg static void
do_warn_function_elimination(gfc_expr * e)889627f7eb2Smrg do_warn_function_elimination (gfc_expr *e)
890627f7eb2Smrg {
891627f7eb2Smrg const char *name;
892627f7eb2Smrg if (e->expr_type == EXPR_FUNCTION
893627f7eb2Smrg && !gfc_pure_function (e, &name) && !gfc_implicit_pure_function (e))
894627f7eb2Smrg {
895627f7eb2Smrg if (name)
896627f7eb2Smrg gfc_warning (OPT_Wfunction_elimination,
897627f7eb2Smrg "Removing call to impure function %qs at %L", name,
898627f7eb2Smrg &(e->where));
899627f7eb2Smrg else
900627f7eb2Smrg gfc_warning (OPT_Wfunction_elimination,
901627f7eb2Smrg "Removing call to impure function at %L",
902627f7eb2Smrg &(e->where));
903627f7eb2Smrg }
904627f7eb2Smrg }
905627f7eb2Smrg
906627f7eb2Smrg
907627f7eb2Smrg /* Callback function for the code walker for doing common function
908627f7eb2Smrg elimination. This builds up the list of functions in the expression
909627f7eb2Smrg and goes through them to detect duplicates, which it then replaces
910627f7eb2Smrg by variables. */
911627f7eb2Smrg
912627f7eb2Smrg static int
cfe_expr_0(gfc_expr ** e,int * walk_subtrees,void * data ATTRIBUTE_UNUSED)913627f7eb2Smrg cfe_expr_0 (gfc_expr **e, int *walk_subtrees,
914627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
915627f7eb2Smrg {
916627f7eb2Smrg int i,j;
917627f7eb2Smrg gfc_expr *newvar;
918627f7eb2Smrg gfc_expr **ei, **ej;
919627f7eb2Smrg
920627f7eb2Smrg /* Don't do this optimization within OMP workshare/atomic or ASSOC lists. */
921627f7eb2Smrg
922627f7eb2Smrg if (in_omp_workshare || in_omp_atomic || in_assoc_list)
923627f7eb2Smrg {
924627f7eb2Smrg *walk_subtrees = 0;
925627f7eb2Smrg return 0;
926627f7eb2Smrg }
927627f7eb2Smrg
928627f7eb2Smrg expr_array.release ();
929627f7eb2Smrg
930627f7eb2Smrg gfc_expr_walker (e, cfe_register_funcs, NULL);
931627f7eb2Smrg
932627f7eb2Smrg /* Walk through all the functions. */
933627f7eb2Smrg
934627f7eb2Smrg FOR_EACH_VEC_ELT_FROM (expr_array, i, ei, 1)
935627f7eb2Smrg {
936627f7eb2Smrg /* Skip if the function has been replaced by a variable already. */
937627f7eb2Smrg if ((*ei)->expr_type == EXPR_VARIABLE)
938627f7eb2Smrg continue;
939627f7eb2Smrg
940627f7eb2Smrg newvar = NULL;
941627f7eb2Smrg for (j=0; j<i; j++)
942627f7eb2Smrg {
943627f7eb2Smrg ej = expr_array[j];
944627f7eb2Smrg if (gfc_dep_compare_functions (*ei, *ej, true) == 0)
945627f7eb2Smrg {
946627f7eb2Smrg if (newvar == NULL)
947627f7eb2Smrg newvar = create_var (*ei, "fcn");
948627f7eb2Smrg
949627f7eb2Smrg if (warn_function_elimination)
950627f7eb2Smrg do_warn_function_elimination (*ej);
951627f7eb2Smrg
952627f7eb2Smrg free (*ej);
953627f7eb2Smrg *ej = gfc_copy_expr (newvar);
954627f7eb2Smrg }
955627f7eb2Smrg }
956627f7eb2Smrg if (newvar)
957627f7eb2Smrg *ei = newvar;
958627f7eb2Smrg }
959627f7eb2Smrg
960627f7eb2Smrg /* We did all the necessary walking in this function. */
961627f7eb2Smrg *walk_subtrees = 0;
962627f7eb2Smrg return 0;
963627f7eb2Smrg }
964627f7eb2Smrg
965627f7eb2Smrg /* Callback function for common function elimination, called from
966627f7eb2Smrg gfc_code_walker. This keeps track of the current code, in order
967627f7eb2Smrg to insert statements as needed. */
968627f7eb2Smrg
969627f7eb2Smrg static int
cfe_code(gfc_code ** c,int * walk_subtrees,void * data ATTRIBUTE_UNUSED)970627f7eb2Smrg cfe_code (gfc_code **c, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
971627f7eb2Smrg {
972627f7eb2Smrg current_code = c;
973627f7eb2Smrg inserted_block = NULL;
974627f7eb2Smrg changed_statement = NULL;
975627f7eb2Smrg
976627f7eb2Smrg /* Do not do anything inside a WHERE statement; scalar assignments, BLOCKs
977627f7eb2Smrg and allocation on assigment are prohibited inside WHERE, and finally
978627f7eb2Smrg masking an expression would lead to wrong-code when replacing
979627f7eb2Smrg
980627f7eb2Smrg WHERE (a>0)
981627f7eb2Smrg b = sum(foo(a) + foo(a))
982627f7eb2Smrg END WHERE
983627f7eb2Smrg
984627f7eb2Smrg with
985627f7eb2Smrg
986627f7eb2Smrg WHERE (a > 0)
987627f7eb2Smrg tmp = foo(a)
988627f7eb2Smrg b = sum(tmp + tmp)
989627f7eb2Smrg END WHERE
990627f7eb2Smrg */
991627f7eb2Smrg
992627f7eb2Smrg if ((*c)->op == EXEC_WHERE)
993627f7eb2Smrg {
994627f7eb2Smrg *walk_subtrees = 0;
995627f7eb2Smrg return 0;
996627f7eb2Smrg }
997627f7eb2Smrg
998627f7eb2Smrg
999627f7eb2Smrg return 0;
1000627f7eb2Smrg }
1001627f7eb2Smrg
1002627f7eb2Smrg /* Dummy function for expression call back, for use when we
1003627f7eb2Smrg really don't want to do any walking. */
1004627f7eb2Smrg
1005627f7eb2Smrg static int
dummy_expr_callback(gfc_expr ** e ATTRIBUTE_UNUSED,int * walk_subtrees,void * data ATTRIBUTE_UNUSED)1006627f7eb2Smrg dummy_expr_callback (gfc_expr **e ATTRIBUTE_UNUSED, int *walk_subtrees,
1007627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
1008627f7eb2Smrg {
1009627f7eb2Smrg *walk_subtrees = 0;
1010627f7eb2Smrg return 0;
1011627f7eb2Smrg }
1012627f7eb2Smrg
1013627f7eb2Smrg /* Dummy function for code callback, for use when we really
1014627f7eb2Smrg don't want to do anything. */
1015627f7eb2Smrg int
gfc_dummy_code_callback(gfc_code ** e ATTRIBUTE_UNUSED,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)1016627f7eb2Smrg gfc_dummy_code_callback (gfc_code **e ATTRIBUTE_UNUSED,
1017627f7eb2Smrg int *walk_subtrees ATTRIBUTE_UNUSED,
1018627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
1019627f7eb2Smrg {
1020627f7eb2Smrg return 0;
1021627f7eb2Smrg }
1022627f7eb2Smrg
1023627f7eb2Smrg /* Code callback function for converting
1024627f7eb2Smrg do while(a)
1025627f7eb2Smrg end do
1026627f7eb2Smrg into the equivalent
1027627f7eb2Smrg do
1028627f7eb2Smrg if (.not. a) exit
1029627f7eb2Smrg end do
1030627f7eb2Smrg This is because common function elimination would otherwise place the
1031627f7eb2Smrg temporary variables outside the loop. */
1032627f7eb2Smrg
1033627f7eb2Smrg static int
convert_do_while(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)1034627f7eb2Smrg convert_do_while (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
1035627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
1036627f7eb2Smrg {
1037627f7eb2Smrg gfc_code *co = *c;
1038627f7eb2Smrg gfc_code *c_if1, *c_if2, *c_exit;
1039627f7eb2Smrg gfc_code *loopblock;
1040627f7eb2Smrg gfc_expr *e_not, *e_cond;
1041627f7eb2Smrg
1042627f7eb2Smrg if (co->op != EXEC_DO_WHILE)
1043627f7eb2Smrg return 0;
1044627f7eb2Smrg
1045627f7eb2Smrg if (co->expr1 == NULL || co->expr1->expr_type == EXPR_CONSTANT)
1046627f7eb2Smrg return 0;
1047627f7eb2Smrg
1048627f7eb2Smrg e_cond = co->expr1;
1049627f7eb2Smrg
1050627f7eb2Smrg /* Generate the condition of the if statement, which is .not. the original
1051627f7eb2Smrg statement. */
1052627f7eb2Smrg e_not = gfc_get_expr ();
1053627f7eb2Smrg e_not->ts = e_cond->ts;
1054627f7eb2Smrg e_not->where = e_cond->where;
1055627f7eb2Smrg e_not->expr_type = EXPR_OP;
1056627f7eb2Smrg e_not->value.op.op = INTRINSIC_NOT;
1057627f7eb2Smrg e_not->value.op.op1 = e_cond;
1058627f7eb2Smrg
1059627f7eb2Smrg /* Generate the EXIT statement. */
1060627f7eb2Smrg c_exit = XCNEW (gfc_code);
1061627f7eb2Smrg c_exit->op = EXEC_EXIT;
1062627f7eb2Smrg c_exit->ext.which_construct = co;
1063627f7eb2Smrg c_exit->loc = co->loc;
1064627f7eb2Smrg
1065627f7eb2Smrg /* Generate the IF statement. */
1066627f7eb2Smrg c_if2 = XCNEW (gfc_code);
1067627f7eb2Smrg c_if2->op = EXEC_IF;
1068627f7eb2Smrg c_if2->expr1 = e_not;
1069627f7eb2Smrg c_if2->next = c_exit;
1070627f7eb2Smrg c_if2->loc = co->loc;
1071627f7eb2Smrg
1072627f7eb2Smrg /* ... plus the one to chain it to. */
1073627f7eb2Smrg c_if1 = XCNEW (gfc_code);
1074627f7eb2Smrg c_if1->op = EXEC_IF;
1075627f7eb2Smrg c_if1->block = c_if2;
1076627f7eb2Smrg c_if1->loc = co->loc;
1077627f7eb2Smrg
1078627f7eb2Smrg /* Make the DO WHILE loop into a DO block by replacing the condition
1079627f7eb2Smrg with a true constant. */
1080627f7eb2Smrg co->expr1 = gfc_get_logical_expr (gfc_default_integer_kind, &co->loc, true);
1081627f7eb2Smrg
1082627f7eb2Smrg /* Hang the generated if statement into the loop body. */
1083627f7eb2Smrg
1084627f7eb2Smrg loopblock = co->block->next;
1085627f7eb2Smrg co->block->next = c_if1;
1086627f7eb2Smrg c_if1->next = loopblock;
1087627f7eb2Smrg
1088627f7eb2Smrg return 0;
1089627f7eb2Smrg }
1090627f7eb2Smrg
1091627f7eb2Smrg /* Code callback function for converting
1092627f7eb2Smrg if (a) then
1093627f7eb2Smrg ...
1094627f7eb2Smrg else if (b) then
1095627f7eb2Smrg end if
1096627f7eb2Smrg
1097627f7eb2Smrg into
1098627f7eb2Smrg if (a) then
1099627f7eb2Smrg else
1100627f7eb2Smrg if (b) then
1101627f7eb2Smrg end if
1102627f7eb2Smrg end if
1103627f7eb2Smrg
1104627f7eb2Smrg because otherwise common function elimination would place the BLOCKs
1105627f7eb2Smrg into the wrong place. */
1106627f7eb2Smrg
1107627f7eb2Smrg static int
convert_elseif(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)1108627f7eb2Smrg convert_elseif (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
1109627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
1110627f7eb2Smrg {
1111627f7eb2Smrg gfc_code *co = *c;
1112627f7eb2Smrg gfc_code *c_if1, *c_if2, *else_stmt;
1113627f7eb2Smrg
1114627f7eb2Smrg if (co->op != EXEC_IF)
1115627f7eb2Smrg return 0;
1116627f7eb2Smrg
1117627f7eb2Smrg /* This loop starts out with the first ELSE statement. */
1118627f7eb2Smrg else_stmt = co->block->block;
1119627f7eb2Smrg
1120627f7eb2Smrg while (else_stmt != NULL)
1121627f7eb2Smrg {
1122627f7eb2Smrg gfc_code *next_else;
1123627f7eb2Smrg
1124627f7eb2Smrg /* If there is no condition, we're done. */
1125627f7eb2Smrg if (else_stmt->expr1 == NULL)
1126627f7eb2Smrg break;
1127627f7eb2Smrg
1128627f7eb2Smrg next_else = else_stmt->block;
1129627f7eb2Smrg
1130627f7eb2Smrg /* Generate the new IF statement. */
1131627f7eb2Smrg c_if2 = XCNEW (gfc_code);
1132627f7eb2Smrg c_if2->op = EXEC_IF;
1133627f7eb2Smrg c_if2->expr1 = else_stmt->expr1;
1134627f7eb2Smrg c_if2->next = else_stmt->next;
1135627f7eb2Smrg c_if2->loc = else_stmt->loc;
1136627f7eb2Smrg c_if2->block = next_else;
1137627f7eb2Smrg
1138627f7eb2Smrg /* ... plus the one to chain it to. */
1139627f7eb2Smrg c_if1 = XCNEW (gfc_code);
1140627f7eb2Smrg c_if1->op = EXEC_IF;
1141627f7eb2Smrg c_if1->block = c_if2;
1142627f7eb2Smrg c_if1->loc = else_stmt->loc;
1143627f7eb2Smrg
1144627f7eb2Smrg /* Insert the new IF after the ELSE. */
1145627f7eb2Smrg else_stmt->expr1 = NULL;
1146627f7eb2Smrg else_stmt->next = c_if1;
1147627f7eb2Smrg else_stmt->block = NULL;
1148627f7eb2Smrg
1149627f7eb2Smrg else_stmt = next_else;
1150627f7eb2Smrg }
1151627f7eb2Smrg /* Don't walk subtrees. */
1152627f7eb2Smrg return 0;
1153627f7eb2Smrg }
1154627f7eb2Smrg
1155627f7eb2Smrg /* Callback function to var_in_expr - return true if expr1 and
1156627f7eb2Smrg expr2 are identical variables. */
1157627f7eb2Smrg static int
var_in_expr_callback(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)1158627f7eb2Smrg var_in_expr_callback (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
1159627f7eb2Smrg void *data)
1160627f7eb2Smrg {
1161627f7eb2Smrg gfc_expr *expr1 = (gfc_expr *) data;
1162627f7eb2Smrg gfc_expr *expr2 = *e;
1163627f7eb2Smrg
1164627f7eb2Smrg if (expr2->expr_type != EXPR_VARIABLE)
1165627f7eb2Smrg return 0;
1166627f7eb2Smrg
1167627f7eb2Smrg return expr1->symtree->n.sym == expr2->symtree->n.sym;
1168627f7eb2Smrg }
1169627f7eb2Smrg
1170627f7eb2Smrg /* Return true if expr1 is found in expr2. */
1171627f7eb2Smrg
1172627f7eb2Smrg static bool
var_in_expr(gfc_expr * expr1,gfc_expr * expr2)1173627f7eb2Smrg var_in_expr (gfc_expr *expr1, gfc_expr *expr2)
1174627f7eb2Smrg {
1175627f7eb2Smrg gcc_assert (expr1->expr_type == EXPR_VARIABLE);
1176627f7eb2Smrg
1177627f7eb2Smrg return gfc_expr_walker (&expr2, var_in_expr_callback, (void *) expr1);
1178627f7eb2Smrg }
1179627f7eb2Smrg
1180627f7eb2Smrg struct do_stack
1181627f7eb2Smrg {
1182627f7eb2Smrg struct do_stack *prev;
1183627f7eb2Smrg gfc_iterator *iter;
1184627f7eb2Smrg gfc_code *code;
1185627f7eb2Smrg } *stack_top;
1186627f7eb2Smrg
1187627f7eb2Smrg /* Recursively traverse the block of a WRITE or READ statement, and maybe
1188627f7eb2Smrg optimize by replacing do loops with their analog array slices. For
1189627f7eb2Smrg example:
1190627f7eb2Smrg
1191627f7eb2Smrg write (*,*) (a(i), i=1,4)
1192627f7eb2Smrg
1193627f7eb2Smrg is replaced with
1194627f7eb2Smrg
1195627f7eb2Smrg write (*,*) a(1:4:1) . */
1196627f7eb2Smrg
1197627f7eb2Smrg static bool
traverse_io_block(gfc_code * code,bool * has_reached,gfc_code * prev)1198627f7eb2Smrg traverse_io_block (gfc_code *code, bool *has_reached, gfc_code *prev)
1199627f7eb2Smrg {
1200627f7eb2Smrg gfc_code *curr;
1201627f7eb2Smrg gfc_expr *new_e, *expr, *start;
1202627f7eb2Smrg gfc_ref *ref;
1203627f7eb2Smrg struct do_stack ds_push;
1204627f7eb2Smrg int i, future_rank = 0;
1205627f7eb2Smrg gfc_iterator *iters[GFC_MAX_DIMENSIONS];
1206627f7eb2Smrg gfc_expr *e;
1207627f7eb2Smrg
1208627f7eb2Smrg /* Find the first transfer/do statement. */
1209627f7eb2Smrg for (curr = code; curr; curr = curr->next)
1210627f7eb2Smrg {
1211627f7eb2Smrg if (curr->op == EXEC_DO || curr->op == EXEC_TRANSFER)
1212627f7eb2Smrg break;
1213627f7eb2Smrg }
1214627f7eb2Smrg
1215627f7eb2Smrg /* Ensure it is the only transfer/do statement because cases like
1216627f7eb2Smrg
1217627f7eb2Smrg write (*,*) (a(i), b(i), i=1,4)
1218627f7eb2Smrg
1219627f7eb2Smrg cannot be optimized. */
1220627f7eb2Smrg
1221627f7eb2Smrg if (!curr || curr->next)
1222627f7eb2Smrg return false;
1223627f7eb2Smrg
1224627f7eb2Smrg if (curr->op == EXEC_DO)
1225627f7eb2Smrg {
1226627f7eb2Smrg if (curr->ext.iterator->var->ref)
1227627f7eb2Smrg return false;
1228627f7eb2Smrg ds_push.prev = stack_top;
1229627f7eb2Smrg ds_push.iter = curr->ext.iterator;
1230627f7eb2Smrg ds_push.code = curr;
1231627f7eb2Smrg stack_top = &ds_push;
1232627f7eb2Smrg if (traverse_io_block (curr->block->next, has_reached, prev))
1233627f7eb2Smrg {
1234627f7eb2Smrg if (curr != stack_top->code && !*has_reached)
1235627f7eb2Smrg {
1236627f7eb2Smrg curr->block->next = NULL;
1237627f7eb2Smrg gfc_free_statements (curr);
1238627f7eb2Smrg }
1239627f7eb2Smrg else
1240627f7eb2Smrg *has_reached = true;
1241627f7eb2Smrg return true;
1242627f7eb2Smrg }
1243627f7eb2Smrg return false;
1244627f7eb2Smrg }
1245627f7eb2Smrg
1246627f7eb2Smrg gcc_assert (curr->op == EXEC_TRANSFER);
1247627f7eb2Smrg
1248627f7eb2Smrg e = curr->expr1;
1249627f7eb2Smrg ref = e->ref;
1250627f7eb2Smrg if (!ref || ref->type != REF_ARRAY || ref->u.ar.codimen != 0 || ref->next)
1251627f7eb2Smrg return false;
1252627f7eb2Smrg
1253627f7eb2Smrg /* Find the iterators belonging to each variable and check conditions. */
1254627f7eb2Smrg for (i = 0; i < ref->u.ar.dimen; i++)
1255627f7eb2Smrg {
1256627f7eb2Smrg if (!ref->u.ar.start[i] || ref->u.ar.start[i]->ref
1257627f7eb2Smrg || ref->u.ar.dimen_type[i] != DIMEN_ELEMENT)
1258627f7eb2Smrg return false;
1259627f7eb2Smrg
1260627f7eb2Smrg start = ref->u.ar.start[i];
1261627f7eb2Smrg gfc_simplify_expr (start, 0);
1262627f7eb2Smrg switch (start->expr_type)
1263627f7eb2Smrg {
1264627f7eb2Smrg case EXPR_VARIABLE:
1265627f7eb2Smrg
1266627f7eb2Smrg /* write (*,*) (a(i), i=a%b,1) not handled yet. */
1267627f7eb2Smrg if (start->ref)
1268627f7eb2Smrg return false;
1269627f7eb2Smrg
1270627f7eb2Smrg /* Check for (a(k), i=1,4) or ((a(j, i), i=1,4), j=1,4). */
1271627f7eb2Smrg if (!stack_top || !stack_top->iter
1272627f7eb2Smrg || stack_top->iter->var->symtree != start->symtree)
1273627f7eb2Smrg {
1274627f7eb2Smrg /* Check for (a(i,i), i=1,3). */
1275627f7eb2Smrg int j;
1276627f7eb2Smrg
1277627f7eb2Smrg for (j=0; j<i; j++)
1278627f7eb2Smrg if (iters[j] && iters[j]->var->symtree == start->symtree)
1279627f7eb2Smrg return false;
1280627f7eb2Smrg
1281627f7eb2Smrg iters[i] = NULL;
1282627f7eb2Smrg }
1283627f7eb2Smrg else
1284627f7eb2Smrg {
1285627f7eb2Smrg iters[i] = stack_top->iter;
1286627f7eb2Smrg stack_top = stack_top->prev;
1287627f7eb2Smrg future_rank++;
1288627f7eb2Smrg }
1289627f7eb2Smrg break;
1290627f7eb2Smrg case EXPR_CONSTANT:
1291627f7eb2Smrg iters[i] = NULL;
1292627f7eb2Smrg break;
1293627f7eb2Smrg case EXPR_OP:
1294627f7eb2Smrg switch (start->value.op.op)
1295627f7eb2Smrg {
1296627f7eb2Smrg case INTRINSIC_PLUS:
1297627f7eb2Smrg case INTRINSIC_TIMES:
1298627f7eb2Smrg if (start->value.op.op1->expr_type != EXPR_VARIABLE)
1299627f7eb2Smrg std::swap (start->value.op.op1, start->value.op.op2);
1300627f7eb2Smrg gcc_fallthrough ();
1301627f7eb2Smrg case INTRINSIC_MINUS:
1302*4c3eb207Smrg if (start->value.op.op1->expr_type!= EXPR_VARIABLE
1303*4c3eb207Smrg || start->value.op.op2->expr_type != EXPR_CONSTANT
1304627f7eb2Smrg || start->value.op.op1->ref)
1305627f7eb2Smrg return false;
1306627f7eb2Smrg if (!stack_top || !stack_top->iter
1307627f7eb2Smrg || stack_top->iter->var->symtree
1308627f7eb2Smrg != start->value.op.op1->symtree)
1309627f7eb2Smrg return false;
1310627f7eb2Smrg iters[i] = stack_top->iter;
1311627f7eb2Smrg stack_top = stack_top->prev;
1312627f7eb2Smrg break;
1313627f7eb2Smrg default:
1314627f7eb2Smrg return false;
1315627f7eb2Smrg }
1316627f7eb2Smrg future_rank++;
1317627f7eb2Smrg break;
1318627f7eb2Smrg default:
1319627f7eb2Smrg return false;
1320627f7eb2Smrg }
1321627f7eb2Smrg }
1322627f7eb2Smrg
1323627f7eb2Smrg /* Check for cases like ((a(i, j), i=1, j), j=1, 2). */
1324627f7eb2Smrg for (int i = 1; i < ref->u.ar.dimen; i++)
1325627f7eb2Smrg {
1326627f7eb2Smrg if (iters[i])
1327627f7eb2Smrg {
1328627f7eb2Smrg gfc_expr *var = iters[i]->var;
1329627f7eb2Smrg for (int j = i - 1; j < i; j++)
1330627f7eb2Smrg {
1331627f7eb2Smrg if (iters[j]
1332627f7eb2Smrg && (var_in_expr (var, iters[j]->start)
1333627f7eb2Smrg || var_in_expr (var, iters[j]->end)
1334627f7eb2Smrg || var_in_expr (var, iters[j]->step)))
1335627f7eb2Smrg return false;
1336627f7eb2Smrg }
1337627f7eb2Smrg }
1338627f7eb2Smrg }
1339627f7eb2Smrg
1340627f7eb2Smrg /* Create new expr. */
1341627f7eb2Smrg new_e = gfc_copy_expr (curr->expr1);
1342627f7eb2Smrg new_e->expr_type = EXPR_VARIABLE;
1343627f7eb2Smrg new_e->rank = future_rank;
1344627f7eb2Smrg if (curr->expr1->shape)
1345627f7eb2Smrg new_e->shape = gfc_get_shape (new_e->rank);
1346627f7eb2Smrg
1347627f7eb2Smrg /* Assign new starts, ends and strides if necessary. */
1348627f7eb2Smrg for (i = 0; i < ref->u.ar.dimen; i++)
1349627f7eb2Smrg {
1350627f7eb2Smrg if (!iters[i])
1351627f7eb2Smrg continue;
1352627f7eb2Smrg start = ref->u.ar.start[i];
1353627f7eb2Smrg switch (start->expr_type)
1354627f7eb2Smrg {
1355627f7eb2Smrg case EXPR_CONSTANT:
1356627f7eb2Smrg gfc_internal_error ("bad expression");
1357627f7eb2Smrg break;
1358627f7eb2Smrg case EXPR_VARIABLE:
1359627f7eb2Smrg new_e->ref->u.ar.dimen_type[i] = DIMEN_RANGE;
1360627f7eb2Smrg new_e->ref->u.ar.type = AR_SECTION;
1361627f7eb2Smrg gfc_free_expr (new_e->ref->u.ar.start[i]);
1362627f7eb2Smrg new_e->ref->u.ar.start[i] = gfc_copy_expr (iters[i]->start);
1363627f7eb2Smrg new_e->ref->u.ar.end[i] = gfc_copy_expr (iters[i]->end);
1364627f7eb2Smrg new_e->ref->u.ar.stride[i] = gfc_copy_expr (iters[i]->step);
1365627f7eb2Smrg break;
1366627f7eb2Smrg case EXPR_OP:
1367627f7eb2Smrg new_e->ref->u.ar.dimen_type[i] = DIMEN_RANGE;
1368627f7eb2Smrg new_e->ref->u.ar.type = AR_SECTION;
1369627f7eb2Smrg gfc_free_expr (new_e->ref->u.ar.start[i]);
1370627f7eb2Smrg expr = gfc_copy_expr (start);
1371627f7eb2Smrg expr->value.op.op1 = gfc_copy_expr (iters[i]->start);
1372627f7eb2Smrg new_e->ref->u.ar.start[i] = expr;
1373627f7eb2Smrg gfc_simplify_expr (new_e->ref->u.ar.start[i], 0);
1374627f7eb2Smrg expr = gfc_copy_expr (start);
1375627f7eb2Smrg expr->value.op.op1 = gfc_copy_expr (iters[i]->end);
1376627f7eb2Smrg new_e->ref->u.ar.end[i] = expr;
1377627f7eb2Smrg gfc_simplify_expr (new_e->ref->u.ar.end[i], 0);
1378627f7eb2Smrg switch (start->value.op.op)
1379627f7eb2Smrg {
1380627f7eb2Smrg case INTRINSIC_MINUS:
1381627f7eb2Smrg case INTRINSIC_PLUS:
1382627f7eb2Smrg new_e->ref->u.ar.stride[i] = gfc_copy_expr (iters[i]->step);
1383627f7eb2Smrg break;
1384627f7eb2Smrg case INTRINSIC_TIMES:
1385627f7eb2Smrg expr = gfc_copy_expr (start);
1386627f7eb2Smrg expr->value.op.op1 = gfc_copy_expr (iters[i]->step);
1387627f7eb2Smrg new_e->ref->u.ar.stride[i] = expr;
1388627f7eb2Smrg gfc_simplify_expr (new_e->ref->u.ar.stride[i], 0);
1389627f7eb2Smrg break;
1390627f7eb2Smrg default:
1391627f7eb2Smrg gfc_internal_error ("bad op");
1392627f7eb2Smrg }
1393627f7eb2Smrg break;
1394627f7eb2Smrg default:
1395627f7eb2Smrg gfc_internal_error ("bad expression");
1396627f7eb2Smrg }
1397627f7eb2Smrg }
1398627f7eb2Smrg curr->expr1 = new_e;
1399627f7eb2Smrg
1400627f7eb2Smrg /* Insert modified statement. Check whether the statement needs to be
1401627f7eb2Smrg inserted at the lowest level. */
1402627f7eb2Smrg if (!stack_top->iter)
1403627f7eb2Smrg {
1404627f7eb2Smrg if (prev)
1405627f7eb2Smrg {
1406627f7eb2Smrg curr->next = prev->next->next;
1407627f7eb2Smrg prev->next = curr;
1408627f7eb2Smrg }
1409627f7eb2Smrg else
1410627f7eb2Smrg {
1411627f7eb2Smrg curr->next = stack_top->code->block->next->next->next;
1412627f7eb2Smrg stack_top->code->block->next = curr;
1413627f7eb2Smrg }
1414627f7eb2Smrg }
1415627f7eb2Smrg else
1416627f7eb2Smrg stack_top->code->block->next = curr;
1417627f7eb2Smrg return true;
1418627f7eb2Smrg }
1419627f7eb2Smrg
1420627f7eb2Smrg /* Function for the gfc_code_walker. If code is a READ or WRITE statement, it
1421627f7eb2Smrg tries to optimize its block. */
1422627f7eb2Smrg
1423627f7eb2Smrg static int
simplify_io_impl_do(gfc_code ** code,int * walk_subtrees,void * data ATTRIBUTE_UNUSED)1424627f7eb2Smrg simplify_io_impl_do (gfc_code **code, int *walk_subtrees,
1425627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
1426627f7eb2Smrg {
1427627f7eb2Smrg gfc_code **curr, *prev = NULL;
1428627f7eb2Smrg struct do_stack write, first;
1429627f7eb2Smrg bool b = false;
1430627f7eb2Smrg *walk_subtrees = 1;
1431627f7eb2Smrg if (!(*code)->block
1432627f7eb2Smrg || ((*code)->block->op != EXEC_WRITE
1433627f7eb2Smrg && (*code)->block->op != EXEC_READ))
1434627f7eb2Smrg return 0;
1435627f7eb2Smrg
1436627f7eb2Smrg *walk_subtrees = 0;
1437627f7eb2Smrg write.prev = NULL;
1438627f7eb2Smrg write.iter = NULL;
1439627f7eb2Smrg write.code = *code;
1440627f7eb2Smrg
1441627f7eb2Smrg for (curr = &(*code)->block; *curr; curr = &(*curr)->next)
1442627f7eb2Smrg {
1443627f7eb2Smrg if ((*curr)->op == EXEC_DO)
1444627f7eb2Smrg {
1445627f7eb2Smrg first.prev = &write;
1446627f7eb2Smrg first.iter = (*curr)->ext.iterator;
1447627f7eb2Smrg first.code = *curr;
1448627f7eb2Smrg stack_top = &first;
1449627f7eb2Smrg traverse_io_block ((*curr)->block->next, &b, prev);
1450627f7eb2Smrg stack_top = NULL;
1451627f7eb2Smrg }
1452627f7eb2Smrg prev = *curr;
1453627f7eb2Smrg }
1454627f7eb2Smrg return 0;
1455627f7eb2Smrg }
1456627f7eb2Smrg
1457627f7eb2Smrg /* Optimize a namespace, including all contained namespaces.
1458627f7eb2Smrg flag_frontend_optimize and flag_fronend_loop_interchange are
1459627f7eb2Smrg handled separately. */
1460627f7eb2Smrg
1461627f7eb2Smrg static void
optimize_namespace(gfc_namespace * ns)1462627f7eb2Smrg optimize_namespace (gfc_namespace *ns)
1463627f7eb2Smrg {
1464627f7eb2Smrg gfc_namespace *saved_ns = gfc_current_ns;
1465627f7eb2Smrg current_ns = ns;
1466627f7eb2Smrg gfc_current_ns = ns;
1467627f7eb2Smrg forall_level = 0;
1468627f7eb2Smrg iterator_level = 0;
1469627f7eb2Smrg in_assoc_list = false;
1470627f7eb2Smrg in_omp_workshare = false;
1471627f7eb2Smrg in_omp_atomic = false;
1472627f7eb2Smrg
1473627f7eb2Smrg if (flag_frontend_optimize)
1474627f7eb2Smrg {
1475627f7eb2Smrg gfc_code_walker (&ns->code, simplify_io_impl_do, dummy_expr_callback, NULL);
1476627f7eb2Smrg gfc_code_walker (&ns->code, convert_do_while, dummy_expr_callback, NULL);
1477627f7eb2Smrg gfc_code_walker (&ns->code, convert_elseif, dummy_expr_callback, NULL);
1478627f7eb2Smrg gfc_code_walker (&ns->code, cfe_code, cfe_expr_0, NULL);
1479627f7eb2Smrg gfc_code_walker (&ns->code, optimize_code, optimize_expr, NULL);
1480627f7eb2Smrg if (flag_inline_matmul_limit != 0 || flag_external_blas)
1481627f7eb2Smrg {
1482627f7eb2Smrg bool found;
1483627f7eb2Smrg do
1484627f7eb2Smrg {
1485627f7eb2Smrg found = false;
1486627f7eb2Smrg gfc_code_walker (&ns->code, matmul_to_var_code, matmul_to_var_expr,
1487627f7eb2Smrg (void *) &found);
1488627f7eb2Smrg }
1489627f7eb2Smrg while (found);
1490627f7eb2Smrg
1491627f7eb2Smrg gfc_code_walker (&ns->code, matmul_temp_args, dummy_expr_callback,
1492627f7eb2Smrg NULL);
1493627f7eb2Smrg }
1494627f7eb2Smrg
1495627f7eb2Smrg if (flag_external_blas)
1496627f7eb2Smrg gfc_code_walker (&ns->code, call_external_blas, dummy_expr_callback,
1497627f7eb2Smrg NULL);
1498627f7eb2Smrg
1499627f7eb2Smrg if (flag_inline_matmul_limit != 0)
1500627f7eb2Smrg gfc_code_walker (&ns->code, inline_matmul_assign, dummy_expr_callback,
1501627f7eb2Smrg NULL);
1502627f7eb2Smrg }
1503627f7eb2Smrg
1504627f7eb2Smrg if (flag_frontend_loop_interchange)
1505627f7eb2Smrg gfc_code_walker (&ns->code, index_interchange, dummy_expr_callback,
1506627f7eb2Smrg NULL);
1507627f7eb2Smrg
1508627f7eb2Smrg /* BLOCKs are handled in the expression walker below. */
1509627f7eb2Smrg for (ns = ns->contained; ns; ns = ns->sibling)
1510627f7eb2Smrg {
1511627f7eb2Smrg if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
1512627f7eb2Smrg optimize_namespace (ns);
1513627f7eb2Smrg }
1514627f7eb2Smrg gfc_current_ns = saved_ns;
1515627f7eb2Smrg }
1516627f7eb2Smrg
1517627f7eb2Smrg /* Handle dependencies for allocatable strings which potentially redefine
1518627f7eb2Smrg themselves in an assignment. */
1519627f7eb2Smrg
1520627f7eb2Smrg static void
realloc_strings(gfc_namespace * ns)1521627f7eb2Smrg realloc_strings (gfc_namespace *ns)
1522627f7eb2Smrg {
1523627f7eb2Smrg current_ns = ns;
1524627f7eb2Smrg gfc_code_walker (&ns->code, realloc_string_callback, dummy_expr_callback, NULL);
1525627f7eb2Smrg
1526627f7eb2Smrg for (ns = ns->contained; ns; ns = ns->sibling)
1527627f7eb2Smrg {
1528627f7eb2Smrg if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
1529627f7eb2Smrg realloc_strings (ns);
1530627f7eb2Smrg }
1531627f7eb2Smrg
1532627f7eb2Smrg }
1533627f7eb2Smrg
1534627f7eb2Smrg static void
optimize_reduction(gfc_namespace * ns)1535627f7eb2Smrg optimize_reduction (gfc_namespace *ns)
1536627f7eb2Smrg {
1537627f7eb2Smrg current_ns = ns;
1538627f7eb2Smrg gfc_code_walker (&ns->code, gfc_dummy_code_callback,
1539627f7eb2Smrg callback_reduction, NULL);
1540627f7eb2Smrg
1541627f7eb2Smrg /* BLOCKs are handled in the expression walker below. */
1542627f7eb2Smrg for (ns = ns->contained; ns; ns = ns->sibling)
1543627f7eb2Smrg {
1544627f7eb2Smrg if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
1545627f7eb2Smrg optimize_reduction (ns);
1546627f7eb2Smrg }
1547627f7eb2Smrg }
1548627f7eb2Smrg
1549627f7eb2Smrg /* Replace code like
1550627f7eb2Smrg a = matmul(b,c) + d
1551627f7eb2Smrg with
1552627f7eb2Smrg a = matmul(b,c) ; a = a + d
1553627f7eb2Smrg where the array function is not elemental and not allocatable
1554627f7eb2Smrg and does not depend on the left-hand side.
1555627f7eb2Smrg */
1556627f7eb2Smrg
1557627f7eb2Smrg static bool
optimize_binop_array_assignment(gfc_code * c,gfc_expr ** rhs,bool seen_op)1558627f7eb2Smrg optimize_binop_array_assignment (gfc_code *c, gfc_expr **rhs, bool seen_op)
1559627f7eb2Smrg {
1560627f7eb2Smrg gfc_expr *e;
1561627f7eb2Smrg
1562627f7eb2Smrg if (!*rhs)
1563627f7eb2Smrg return false;
1564627f7eb2Smrg
1565627f7eb2Smrg e = *rhs;
1566627f7eb2Smrg if (e->expr_type == EXPR_OP)
1567627f7eb2Smrg {
1568627f7eb2Smrg switch (e->value.op.op)
1569627f7eb2Smrg {
1570627f7eb2Smrg /* Unary operators and exponentiation: Only look at a single
1571627f7eb2Smrg operand. */
1572627f7eb2Smrg case INTRINSIC_NOT:
1573627f7eb2Smrg case INTRINSIC_UPLUS:
1574627f7eb2Smrg case INTRINSIC_UMINUS:
1575627f7eb2Smrg case INTRINSIC_PARENTHESES:
1576627f7eb2Smrg case INTRINSIC_POWER:
1577627f7eb2Smrg if (optimize_binop_array_assignment (c, &e->value.op.op1, seen_op))
1578627f7eb2Smrg return true;
1579627f7eb2Smrg break;
1580627f7eb2Smrg
1581627f7eb2Smrg case INTRINSIC_CONCAT:
1582627f7eb2Smrg /* Do not do string concatenations. */
1583627f7eb2Smrg break;
1584627f7eb2Smrg
1585627f7eb2Smrg default:
1586627f7eb2Smrg /* Binary operators. */
1587627f7eb2Smrg if (optimize_binop_array_assignment (c, &e->value.op.op1, true))
1588627f7eb2Smrg return true;
1589627f7eb2Smrg
1590627f7eb2Smrg if (optimize_binop_array_assignment (c, &e->value.op.op2, true))
1591627f7eb2Smrg return true;
1592627f7eb2Smrg
1593627f7eb2Smrg break;
1594627f7eb2Smrg }
1595627f7eb2Smrg }
1596627f7eb2Smrg else if (seen_op && e->expr_type == EXPR_FUNCTION && e->rank > 0
1597627f7eb2Smrg && ! (e->value.function.esym
1598627f7eb2Smrg && (e->value.function.esym->attr.elemental
1599627f7eb2Smrg || e->value.function.esym->attr.allocatable
1600627f7eb2Smrg || e->value.function.esym->ts.type != c->expr1->ts.type
1601627f7eb2Smrg || e->value.function.esym->ts.kind != c->expr1->ts.kind))
1602627f7eb2Smrg && ! (e->value.function.isym
1603627f7eb2Smrg && (e->value.function.isym->elemental
1604627f7eb2Smrg || e->ts.type != c->expr1->ts.type
1605627f7eb2Smrg || e->ts.kind != c->expr1->ts.kind))
1606627f7eb2Smrg && ! gfc_inline_intrinsic_function_p (e))
1607627f7eb2Smrg {
1608627f7eb2Smrg
1609627f7eb2Smrg gfc_code *n;
1610627f7eb2Smrg gfc_expr *new_expr;
1611627f7eb2Smrg
1612627f7eb2Smrg /* Insert a new assignment statement after the current one. */
1613627f7eb2Smrg n = XCNEW (gfc_code);
1614627f7eb2Smrg n->op = EXEC_ASSIGN;
1615627f7eb2Smrg n->loc = c->loc;
1616627f7eb2Smrg n->next = c->next;
1617627f7eb2Smrg c->next = n;
1618627f7eb2Smrg
1619627f7eb2Smrg n->expr1 = gfc_copy_expr (c->expr1);
1620627f7eb2Smrg n->expr2 = c->expr2;
1621627f7eb2Smrg new_expr = gfc_copy_expr (c->expr1);
1622627f7eb2Smrg c->expr2 = e;
1623627f7eb2Smrg *rhs = new_expr;
1624627f7eb2Smrg
1625627f7eb2Smrg return true;
1626627f7eb2Smrg
1627627f7eb2Smrg }
1628627f7eb2Smrg
1629627f7eb2Smrg /* Nothing to optimize. */
1630627f7eb2Smrg return false;
1631627f7eb2Smrg }
1632627f7eb2Smrg
1633627f7eb2Smrg /* Remove unneeded TRIMs at the end of expressions. */
1634627f7eb2Smrg
1635627f7eb2Smrg static bool
remove_trim(gfc_expr * rhs)1636627f7eb2Smrg remove_trim (gfc_expr *rhs)
1637627f7eb2Smrg {
1638627f7eb2Smrg bool ret;
1639627f7eb2Smrg
1640627f7eb2Smrg ret = false;
1641627f7eb2Smrg if (!rhs)
1642627f7eb2Smrg return ret;
1643627f7eb2Smrg
1644627f7eb2Smrg /* Check for a // b // trim(c). Looping is probably not
1645627f7eb2Smrg necessary because the parser usually generates
1646627f7eb2Smrg (// (// a b ) trim(c) ) , but better safe than sorry. */
1647627f7eb2Smrg
1648627f7eb2Smrg while (rhs->expr_type == EXPR_OP
1649627f7eb2Smrg && rhs->value.op.op == INTRINSIC_CONCAT)
1650627f7eb2Smrg rhs = rhs->value.op.op2;
1651627f7eb2Smrg
1652627f7eb2Smrg while (rhs->expr_type == EXPR_FUNCTION && rhs->value.function.isym
1653627f7eb2Smrg && rhs->value.function.isym->id == GFC_ISYM_TRIM)
1654627f7eb2Smrg {
1655627f7eb2Smrg strip_function_call (rhs);
1656627f7eb2Smrg /* Recursive call to catch silly stuff like trim ( a // trim(b)). */
1657627f7eb2Smrg remove_trim (rhs);
1658627f7eb2Smrg ret = true;
1659627f7eb2Smrg }
1660627f7eb2Smrg
1661627f7eb2Smrg return ret;
1662627f7eb2Smrg }
1663627f7eb2Smrg
1664627f7eb2Smrg /* Optimizations for an assignment. */
1665627f7eb2Smrg
1666627f7eb2Smrg static void
optimize_assignment(gfc_code * c)1667627f7eb2Smrg optimize_assignment (gfc_code * c)
1668627f7eb2Smrg {
1669627f7eb2Smrg gfc_expr *lhs, *rhs;
1670627f7eb2Smrg
1671627f7eb2Smrg lhs = c->expr1;
1672627f7eb2Smrg rhs = c->expr2;
1673627f7eb2Smrg
1674627f7eb2Smrg if (lhs->ts.type == BT_CHARACTER && !lhs->ts.deferred)
1675627f7eb2Smrg {
1676627f7eb2Smrg /* Optimize a = trim(b) to a = b. */
1677627f7eb2Smrg remove_trim (rhs);
1678627f7eb2Smrg
1679627f7eb2Smrg /* Replace a = ' ' by a = '' to optimize away a memcpy. */
1680627f7eb2Smrg if (is_empty_string (rhs))
1681627f7eb2Smrg rhs->value.character.length = 0;
1682627f7eb2Smrg }
1683627f7eb2Smrg
1684627f7eb2Smrg if (lhs->rank > 0 && gfc_check_dependency (lhs, rhs, true) == 0)
1685627f7eb2Smrg optimize_binop_array_assignment (c, &rhs, false);
1686627f7eb2Smrg }
1687627f7eb2Smrg
1688627f7eb2Smrg
1689627f7eb2Smrg /* Remove an unneeded function call, modifying the expression.
1690627f7eb2Smrg This replaces the function call with the value of its
1691627f7eb2Smrg first argument. The rest of the argument list is freed. */
1692627f7eb2Smrg
1693627f7eb2Smrg static void
strip_function_call(gfc_expr * e)1694627f7eb2Smrg strip_function_call (gfc_expr *e)
1695627f7eb2Smrg {
1696627f7eb2Smrg gfc_expr *e1;
1697627f7eb2Smrg gfc_actual_arglist *a;
1698627f7eb2Smrg
1699627f7eb2Smrg a = e->value.function.actual;
1700627f7eb2Smrg
1701627f7eb2Smrg /* We should have at least one argument. */
1702627f7eb2Smrg gcc_assert (a->expr != NULL);
1703627f7eb2Smrg
1704627f7eb2Smrg e1 = a->expr;
1705627f7eb2Smrg
1706627f7eb2Smrg /* Free the remaining arglist, if any. */
1707627f7eb2Smrg if (a->next)
1708627f7eb2Smrg gfc_free_actual_arglist (a->next);
1709627f7eb2Smrg
1710627f7eb2Smrg /* Graft the argument expression onto the original function. */
1711627f7eb2Smrg *e = *e1;
1712627f7eb2Smrg free (e1);
1713627f7eb2Smrg
1714627f7eb2Smrg }
1715627f7eb2Smrg
1716627f7eb2Smrg /* Optimization of lexical comparison functions. */
1717627f7eb2Smrg
1718627f7eb2Smrg static bool
optimize_lexical_comparison(gfc_expr * e)1719627f7eb2Smrg optimize_lexical_comparison (gfc_expr *e)
1720627f7eb2Smrg {
1721627f7eb2Smrg if (e->expr_type != EXPR_FUNCTION || e->value.function.isym == NULL)
1722627f7eb2Smrg return false;
1723627f7eb2Smrg
1724627f7eb2Smrg switch (e->value.function.isym->id)
1725627f7eb2Smrg {
1726627f7eb2Smrg case GFC_ISYM_LLE:
1727627f7eb2Smrg return optimize_comparison (e, INTRINSIC_LE);
1728627f7eb2Smrg
1729627f7eb2Smrg case GFC_ISYM_LGE:
1730627f7eb2Smrg return optimize_comparison (e, INTRINSIC_GE);
1731627f7eb2Smrg
1732627f7eb2Smrg case GFC_ISYM_LGT:
1733627f7eb2Smrg return optimize_comparison (e, INTRINSIC_GT);
1734627f7eb2Smrg
1735627f7eb2Smrg case GFC_ISYM_LLT:
1736627f7eb2Smrg return optimize_comparison (e, INTRINSIC_LT);
1737627f7eb2Smrg
1738627f7eb2Smrg default:
1739627f7eb2Smrg break;
1740627f7eb2Smrg }
1741627f7eb2Smrg return false;
1742627f7eb2Smrg }
1743627f7eb2Smrg
1744627f7eb2Smrg /* Combine stuff like [a]>b into [a>b], for easier optimization later. Do not
1745627f7eb2Smrg do CHARACTER because of possible pessimization involving character
1746627f7eb2Smrg lengths. */
1747627f7eb2Smrg
1748627f7eb2Smrg static bool
combine_array_constructor(gfc_expr * e)1749627f7eb2Smrg combine_array_constructor (gfc_expr *e)
1750627f7eb2Smrg {
1751627f7eb2Smrg
1752627f7eb2Smrg gfc_expr *op1, *op2;
1753627f7eb2Smrg gfc_expr *scalar;
1754627f7eb2Smrg gfc_expr *new_expr;
1755627f7eb2Smrg gfc_constructor *c, *new_c;
1756627f7eb2Smrg gfc_constructor_base oldbase, newbase;
1757627f7eb2Smrg bool scalar_first;
1758627f7eb2Smrg int n_elem;
1759627f7eb2Smrg bool all_const;
1760627f7eb2Smrg
1761627f7eb2Smrg /* Array constructors have rank one. */
1762627f7eb2Smrg if (e->rank != 1)
1763627f7eb2Smrg return false;
1764627f7eb2Smrg
1765627f7eb2Smrg /* Don't try to combine association lists, this makes no sense
1766627f7eb2Smrg and leads to an ICE. */
1767627f7eb2Smrg if (in_assoc_list)
1768627f7eb2Smrg return false;
1769627f7eb2Smrg
1770627f7eb2Smrg /* With FORALL, the BLOCKS created by create_var will cause an ICE. */
1771627f7eb2Smrg if (forall_level > 0)
1772627f7eb2Smrg return false;
1773627f7eb2Smrg
1774627f7eb2Smrg /* Inside an iterator, things can get hairy; we are likely to create
1775627f7eb2Smrg an invalid temporary variable. */
1776627f7eb2Smrg if (iterator_level > 0)
1777627f7eb2Smrg return false;
1778627f7eb2Smrg
1779627f7eb2Smrg /* WHERE also doesn't work. */
1780627f7eb2Smrg if (in_where > 0)
1781627f7eb2Smrg return false;
1782627f7eb2Smrg
1783627f7eb2Smrg op1 = e->value.op.op1;
1784627f7eb2Smrg op2 = e->value.op.op2;
1785627f7eb2Smrg
1786627f7eb2Smrg if (!op1 || !op2)
1787627f7eb2Smrg return false;
1788627f7eb2Smrg
1789627f7eb2Smrg if (op1->expr_type == EXPR_ARRAY && op2->rank == 0)
1790627f7eb2Smrg scalar_first = false;
1791627f7eb2Smrg else if (op2->expr_type == EXPR_ARRAY && op1->rank == 0)
1792627f7eb2Smrg {
1793627f7eb2Smrg scalar_first = true;
1794627f7eb2Smrg op1 = e->value.op.op2;
1795627f7eb2Smrg op2 = e->value.op.op1;
1796627f7eb2Smrg }
1797627f7eb2Smrg else
1798627f7eb2Smrg return false;
1799627f7eb2Smrg
1800627f7eb2Smrg if (op2->ts.type == BT_CHARACTER)
1801627f7eb2Smrg return false;
1802627f7eb2Smrg
1803627f7eb2Smrg /* This might be an expanded constructor with very many constant values. If
1804627f7eb2Smrg we perform the operation here, we might end up with a long compile time
1805627f7eb2Smrg and actually longer execution time, so a length bound is in order here.
1806627f7eb2Smrg If the constructor constains something which is not a constant, it did
1807627f7eb2Smrg not come from an expansion, so leave it alone. */
1808627f7eb2Smrg
1809627f7eb2Smrg #define CONSTR_LEN_MAX 4
1810627f7eb2Smrg
1811627f7eb2Smrg oldbase = op1->value.constructor;
1812627f7eb2Smrg
1813627f7eb2Smrg n_elem = 0;
1814627f7eb2Smrg all_const = true;
1815627f7eb2Smrg for (c = gfc_constructor_first (oldbase); c; c = gfc_constructor_next(c))
1816627f7eb2Smrg {
1817627f7eb2Smrg if (c->expr->expr_type != EXPR_CONSTANT)
1818627f7eb2Smrg {
1819627f7eb2Smrg all_const = false;
1820627f7eb2Smrg break;
1821627f7eb2Smrg }
1822627f7eb2Smrg n_elem += 1;
1823627f7eb2Smrg }
1824627f7eb2Smrg
1825627f7eb2Smrg if (all_const && n_elem > CONSTR_LEN_MAX)
1826627f7eb2Smrg return false;
1827627f7eb2Smrg
1828627f7eb2Smrg #undef CONSTR_LEN_MAX
1829627f7eb2Smrg
1830627f7eb2Smrg newbase = NULL;
1831627f7eb2Smrg e->expr_type = EXPR_ARRAY;
1832627f7eb2Smrg
1833627f7eb2Smrg scalar = create_var (gfc_copy_expr (op2), "constr");
1834627f7eb2Smrg
1835627f7eb2Smrg for (c = gfc_constructor_first (oldbase); c;
1836627f7eb2Smrg c = gfc_constructor_next (c))
1837627f7eb2Smrg {
1838627f7eb2Smrg new_expr = gfc_get_expr ();
1839627f7eb2Smrg new_expr->ts = e->ts;
1840627f7eb2Smrg new_expr->expr_type = EXPR_OP;
1841627f7eb2Smrg new_expr->rank = c->expr->rank;
1842627f7eb2Smrg new_expr->where = c->expr->where;
1843627f7eb2Smrg new_expr->value.op.op = e->value.op.op;
1844627f7eb2Smrg
1845627f7eb2Smrg if (scalar_first)
1846627f7eb2Smrg {
1847627f7eb2Smrg new_expr->value.op.op1 = gfc_copy_expr (scalar);
1848627f7eb2Smrg new_expr->value.op.op2 = gfc_copy_expr (c->expr);
1849627f7eb2Smrg }
1850627f7eb2Smrg else
1851627f7eb2Smrg {
1852627f7eb2Smrg new_expr->value.op.op1 = gfc_copy_expr (c->expr);
1853627f7eb2Smrg new_expr->value.op.op2 = gfc_copy_expr (scalar);
1854627f7eb2Smrg }
1855627f7eb2Smrg
1856627f7eb2Smrg new_c = gfc_constructor_append_expr (&newbase, new_expr, &(e->where));
1857627f7eb2Smrg new_c->iterator = c->iterator;
1858627f7eb2Smrg c->iterator = NULL;
1859627f7eb2Smrg }
1860627f7eb2Smrg
1861627f7eb2Smrg gfc_free_expr (op1);
1862627f7eb2Smrg gfc_free_expr (op2);
1863627f7eb2Smrg gfc_free_expr (scalar);
1864627f7eb2Smrg
1865627f7eb2Smrg e->value.constructor = newbase;
1866627f7eb2Smrg return true;
1867627f7eb2Smrg }
1868627f7eb2Smrg
1869627f7eb2Smrg /* Recursive optimization of operators. */
1870627f7eb2Smrg
1871627f7eb2Smrg static bool
optimize_op(gfc_expr * e)1872627f7eb2Smrg optimize_op (gfc_expr *e)
1873627f7eb2Smrg {
1874627f7eb2Smrg bool changed;
1875627f7eb2Smrg
1876627f7eb2Smrg gfc_intrinsic_op op = e->value.op.op;
1877627f7eb2Smrg
1878627f7eb2Smrg changed = false;
1879627f7eb2Smrg
1880627f7eb2Smrg /* Only use new-style comparisons. */
1881627f7eb2Smrg switch(op)
1882627f7eb2Smrg {
1883627f7eb2Smrg case INTRINSIC_EQ_OS:
1884627f7eb2Smrg op = INTRINSIC_EQ;
1885627f7eb2Smrg break;
1886627f7eb2Smrg
1887627f7eb2Smrg case INTRINSIC_GE_OS:
1888627f7eb2Smrg op = INTRINSIC_GE;
1889627f7eb2Smrg break;
1890627f7eb2Smrg
1891627f7eb2Smrg case INTRINSIC_LE_OS:
1892627f7eb2Smrg op = INTRINSIC_LE;
1893627f7eb2Smrg break;
1894627f7eb2Smrg
1895627f7eb2Smrg case INTRINSIC_NE_OS:
1896627f7eb2Smrg op = INTRINSIC_NE;
1897627f7eb2Smrg break;
1898627f7eb2Smrg
1899627f7eb2Smrg case INTRINSIC_GT_OS:
1900627f7eb2Smrg op = INTRINSIC_GT;
1901627f7eb2Smrg break;
1902627f7eb2Smrg
1903627f7eb2Smrg case INTRINSIC_LT_OS:
1904627f7eb2Smrg op = INTRINSIC_LT;
1905627f7eb2Smrg break;
1906627f7eb2Smrg
1907627f7eb2Smrg default:
1908627f7eb2Smrg break;
1909627f7eb2Smrg }
1910627f7eb2Smrg
1911627f7eb2Smrg switch (op)
1912627f7eb2Smrg {
1913627f7eb2Smrg case INTRINSIC_EQ:
1914627f7eb2Smrg case INTRINSIC_GE:
1915627f7eb2Smrg case INTRINSIC_LE:
1916627f7eb2Smrg case INTRINSIC_NE:
1917627f7eb2Smrg case INTRINSIC_GT:
1918627f7eb2Smrg case INTRINSIC_LT:
1919627f7eb2Smrg changed = optimize_comparison (e, op);
1920627f7eb2Smrg
1921627f7eb2Smrg gcc_fallthrough ();
1922627f7eb2Smrg /* Look at array constructors. */
1923627f7eb2Smrg case INTRINSIC_PLUS:
1924627f7eb2Smrg case INTRINSIC_MINUS:
1925627f7eb2Smrg case INTRINSIC_TIMES:
1926627f7eb2Smrg case INTRINSIC_DIVIDE:
1927627f7eb2Smrg return combine_array_constructor (e) || changed;
1928627f7eb2Smrg
1929627f7eb2Smrg default:
1930627f7eb2Smrg break;
1931627f7eb2Smrg }
1932627f7eb2Smrg
1933627f7eb2Smrg return false;
1934627f7eb2Smrg }
1935627f7eb2Smrg
1936627f7eb2Smrg
1937627f7eb2Smrg /* Return true if a constant string contains only blanks. */
1938627f7eb2Smrg
1939627f7eb2Smrg static bool
is_empty_string(gfc_expr * e)1940627f7eb2Smrg is_empty_string (gfc_expr *e)
1941627f7eb2Smrg {
1942627f7eb2Smrg int i;
1943627f7eb2Smrg
1944627f7eb2Smrg if (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_CONSTANT)
1945627f7eb2Smrg return false;
1946627f7eb2Smrg
1947627f7eb2Smrg for (i=0; i < e->value.character.length; i++)
1948627f7eb2Smrg {
1949627f7eb2Smrg if (e->value.character.string[i] != ' ')
1950627f7eb2Smrg return false;
1951627f7eb2Smrg }
1952627f7eb2Smrg
1953627f7eb2Smrg return true;
1954627f7eb2Smrg }
1955627f7eb2Smrg
1956627f7eb2Smrg
1957627f7eb2Smrg /* Insert a call to the intrinsic len_trim. Use a different name for
1958627f7eb2Smrg the symbol tree so we don't run into trouble when the user has
1959627f7eb2Smrg renamed len_trim for some reason. */
1960627f7eb2Smrg
1961627f7eb2Smrg static gfc_expr*
get_len_trim_call(gfc_expr * str,int kind)1962627f7eb2Smrg get_len_trim_call (gfc_expr *str, int kind)
1963627f7eb2Smrg {
1964627f7eb2Smrg gfc_expr *fcn;
1965627f7eb2Smrg gfc_actual_arglist *actual_arglist, *next;
1966627f7eb2Smrg
1967627f7eb2Smrg fcn = gfc_get_expr ();
1968627f7eb2Smrg fcn->expr_type = EXPR_FUNCTION;
1969627f7eb2Smrg fcn->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_LEN_TRIM);
1970627f7eb2Smrg actual_arglist = gfc_get_actual_arglist ();
1971627f7eb2Smrg actual_arglist->expr = str;
1972627f7eb2Smrg next = gfc_get_actual_arglist ();
1973627f7eb2Smrg next->expr = gfc_get_int_expr (gfc_default_integer_kind, NULL, kind);
1974627f7eb2Smrg actual_arglist->next = next;
1975627f7eb2Smrg
1976627f7eb2Smrg fcn->value.function.actual = actual_arglist;
1977627f7eb2Smrg fcn->where = str->where;
1978627f7eb2Smrg fcn->ts.type = BT_INTEGER;
1979627f7eb2Smrg fcn->ts.kind = gfc_charlen_int_kind;
1980627f7eb2Smrg
1981627f7eb2Smrg gfc_get_sym_tree ("__internal_len_trim", current_ns, &fcn->symtree, false);
1982627f7eb2Smrg fcn->symtree->n.sym->ts = fcn->ts;
1983627f7eb2Smrg fcn->symtree->n.sym->attr.flavor = FL_PROCEDURE;
1984627f7eb2Smrg fcn->symtree->n.sym->attr.function = 1;
1985627f7eb2Smrg fcn->symtree->n.sym->attr.elemental = 1;
1986627f7eb2Smrg fcn->symtree->n.sym->attr.referenced = 1;
1987627f7eb2Smrg fcn->symtree->n.sym->attr.access = ACCESS_PRIVATE;
1988627f7eb2Smrg gfc_commit_symbol (fcn->symtree->n.sym);
1989627f7eb2Smrg
1990627f7eb2Smrg return fcn;
1991627f7eb2Smrg }
1992627f7eb2Smrg
1993627f7eb2Smrg
1994627f7eb2Smrg /* Optimize expressions for equality. */
1995627f7eb2Smrg
1996627f7eb2Smrg static bool
optimize_comparison(gfc_expr * e,gfc_intrinsic_op op)1997627f7eb2Smrg optimize_comparison (gfc_expr *e, gfc_intrinsic_op op)
1998627f7eb2Smrg {
1999627f7eb2Smrg gfc_expr *op1, *op2;
2000627f7eb2Smrg bool change;
2001627f7eb2Smrg int eq;
2002627f7eb2Smrg bool result;
2003627f7eb2Smrg gfc_actual_arglist *firstarg, *secondarg;
2004627f7eb2Smrg
2005627f7eb2Smrg if (e->expr_type == EXPR_OP)
2006627f7eb2Smrg {
2007627f7eb2Smrg firstarg = NULL;
2008627f7eb2Smrg secondarg = NULL;
2009627f7eb2Smrg op1 = e->value.op.op1;
2010627f7eb2Smrg op2 = e->value.op.op2;
2011627f7eb2Smrg }
2012627f7eb2Smrg else if (e->expr_type == EXPR_FUNCTION)
2013627f7eb2Smrg {
2014627f7eb2Smrg /* One of the lexical comparison functions. */
2015627f7eb2Smrg firstarg = e->value.function.actual;
2016627f7eb2Smrg secondarg = firstarg->next;
2017627f7eb2Smrg op1 = firstarg->expr;
2018627f7eb2Smrg op2 = secondarg->expr;
2019627f7eb2Smrg }
2020627f7eb2Smrg else
2021627f7eb2Smrg gcc_unreachable ();
2022627f7eb2Smrg
2023627f7eb2Smrg /* Strip off unneeded TRIM calls from string comparisons. */
2024627f7eb2Smrg
2025627f7eb2Smrg change = remove_trim (op1);
2026627f7eb2Smrg
2027627f7eb2Smrg if (remove_trim (op2))
2028627f7eb2Smrg change = true;
2029627f7eb2Smrg
2030627f7eb2Smrg /* An expression of type EXPR_CONSTANT is only valid for scalars. */
2031627f7eb2Smrg /* TODO: A scalar constant may be acceptable in some cases (the scalarizer
2032627f7eb2Smrg handles them well). However, there are also cases that need a non-scalar
2033627f7eb2Smrg argument. For example the any intrinsic. See PR 45380. */
2034627f7eb2Smrg if (e->rank > 0)
2035627f7eb2Smrg return change;
2036627f7eb2Smrg
2037627f7eb2Smrg /* Replace a == '' with len_trim(a) == 0 and a /= '' with
2038627f7eb2Smrg len_trim(a) != 0 */
2039627f7eb2Smrg if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER
2040627f7eb2Smrg && (op == INTRINSIC_EQ || op == INTRINSIC_NE))
2041627f7eb2Smrg {
2042627f7eb2Smrg bool empty_op1, empty_op2;
2043627f7eb2Smrg empty_op1 = is_empty_string (op1);
2044627f7eb2Smrg empty_op2 = is_empty_string (op2);
2045627f7eb2Smrg
2046627f7eb2Smrg if (empty_op1 || empty_op2)
2047627f7eb2Smrg {
2048627f7eb2Smrg gfc_expr *fcn;
2049627f7eb2Smrg gfc_expr *zero;
2050627f7eb2Smrg gfc_expr *str;
2051627f7eb2Smrg
2052627f7eb2Smrg /* This can only happen when an error for comparing
2053627f7eb2Smrg characters of different kinds has already been issued. */
2054627f7eb2Smrg if (empty_op1 && empty_op2)
2055627f7eb2Smrg return false;
2056627f7eb2Smrg
2057627f7eb2Smrg zero = gfc_get_int_expr (gfc_charlen_int_kind, &e->where, 0);
2058627f7eb2Smrg str = empty_op1 ? op2 : op1;
2059627f7eb2Smrg
2060627f7eb2Smrg fcn = get_len_trim_call (str, gfc_charlen_int_kind);
2061627f7eb2Smrg
2062627f7eb2Smrg
2063627f7eb2Smrg if (empty_op1)
2064627f7eb2Smrg gfc_free_expr (op1);
2065627f7eb2Smrg else
2066627f7eb2Smrg gfc_free_expr (op2);
2067627f7eb2Smrg
2068627f7eb2Smrg op1 = fcn;
2069627f7eb2Smrg op2 = zero;
2070627f7eb2Smrg e->value.op.op1 = fcn;
2071627f7eb2Smrg e->value.op.op2 = zero;
2072627f7eb2Smrg }
2073627f7eb2Smrg }
2074627f7eb2Smrg
2075627f7eb2Smrg
2076627f7eb2Smrg /* Don't compare REAL or COMPLEX expressions when honoring NaNs. */
2077627f7eb2Smrg
2078627f7eb2Smrg if (flag_finite_math_only
2079627f7eb2Smrg || (op1->ts.type != BT_REAL && op2->ts.type != BT_REAL
2080627f7eb2Smrg && op1->ts.type != BT_COMPLEX && op2->ts.type != BT_COMPLEX))
2081627f7eb2Smrg {
2082627f7eb2Smrg eq = gfc_dep_compare_expr (op1, op2);
2083627f7eb2Smrg if (eq <= -2)
2084627f7eb2Smrg {
2085627f7eb2Smrg /* Replace A // B < A // C with B < C, and A // B < C // B
2086627f7eb2Smrg with A < C. */
2087627f7eb2Smrg if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER
2088627f7eb2Smrg && op1->expr_type == EXPR_OP
2089627f7eb2Smrg && op1->value.op.op == INTRINSIC_CONCAT
2090627f7eb2Smrg && op2->expr_type == EXPR_OP
2091627f7eb2Smrg && op2->value.op.op == INTRINSIC_CONCAT)
2092627f7eb2Smrg {
2093627f7eb2Smrg gfc_expr *op1_left = op1->value.op.op1;
2094627f7eb2Smrg gfc_expr *op2_left = op2->value.op.op1;
2095627f7eb2Smrg gfc_expr *op1_right = op1->value.op.op2;
2096627f7eb2Smrg gfc_expr *op2_right = op2->value.op.op2;
2097627f7eb2Smrg
2098627f7eb2Smrg if (gfc_dep_compare_expr (op1_left, op2_left) == 0)
2099627f7eb2Smrg {
2100627f7eb2Smrg /* Watch out for 'A ' // x vs. 'A' // x. */
2101627f7eb2Smrg
2102627f7eb2Smrg if (op1_left->expr_type == EXPR_CONSTANT
2103627f7eb2Smrg && op2_left->expr_type == EXPR_CONSTANT
2104627f7eb2Smrg && op1_left->value.character.length
2105627f7eb2Smrg != op2_left->value.character.length)
2106627f7eb2Smrg return change;
2107627f7eb2Smrg else
2108627f7eb2Smrg {
2109627f7eb2Smrg free (op1_left);
2110627f7eb2Smrg free (op2_left);
2111627f7eb2Smrg if (firstarg)
2112627f7eb2Smrg {
2113627f7eb2Smrg firstarg->expr = op1_right;
2114627f7eb2Smrg secondarg->expr = op2_right;
2115627f7eb2Smrg }
2116627f7eb2Smrg else
2117627f7eb2Smrg {
2118627f7eb2Smrg e->value.op.op1 = op1_right;
2119627f7eb2Smrg e->value.op.op2 = op2_right;
2120627f7eb2Smrg }
2121627f7eb2Smrg optimize_comparison (e, op);
2122627f7eb2Smrg return true;
2123627f7eb2Smrg }
2124627f7eb2Smrg }
2125627f7eb2Smrg if (gfc_dep_compare_expr (op1_right, op2_right) == 0)
2126627f7eb2Smrg {
2127627f7eb2Smrg free (op1_right);
2128627f7eb2Smrg free (op2_right);
2129627f7eb2Smrg if (firstarg)
2130627f7eb2Smrg {
2131627f7eb2Smrg firstarg->expr = op1_left;
2132627f7eb2Smrg secondarg->expr = op2_left;
2133627f7eb2Smrg }
2134627f7eb2Smrg else
2135627f7eb2Smrg {
2136627f7eb2Smrg e->value.op.op1 = op1_left;
2137627f7eb2Smrg e->value.op.op2 = op2_left;
2138627f7eb2Smrg }
2139627f7eb2Smrg
2140627f7eb2Smrg optimize_comparison (e, op);
2141627f7eb2Smrg return true;
2142627f7eb2Smrg }
2143627f7eb2Smrg }
2144627f7eb2Smrg }
2145627f7eb2Smrg else
2146627f7eb2Smrg {
2147627f7eb2Smrg /* eq can only be -1, 0 or 1 at this point. */
2148627f7eb2Smrg switch (op)
2149627f7eb2Smrg {
2150627f7eb2Smrg case INTRINSIC_EQ:
2151627f7eb2Smrg result = eq == 0;
2152627f7eb2Smrg break;
2153627f7eb2Smrg
2154627f7eb2Smrg case INTRINSIC_GE:
2155627f7eb2Smrg result = eq >= 0;
2156627f7eb2Smrg break;
2157627f7eb2Smrg
2158627f7eb2Smrg case INTRINSIC_LE:
2159627f7eb2Smrg result = eq <= 0;
2160627f7eb2Smrg break;
2161627f7eb2Smrg
2162627f7eb2Smrg case INTRINSIC_NE:
2163627f7eb2Smrg result = eq != 0;
2164627f7eb2Smrg break;
2165627f7eb2Smrg
2166627f7eb2Smrg case INTRINSIC_GT:
2167627f7eb2Smrg result = eq > 0;
2168627f7eb2Smrg break;
2169627f7eb2Smrg
2170627f7eb2Smrg case INTRINSIC_LT:
2171627f7eb2Smrg result = eq < 0;
2172627f7eb2Smrg break;
2173627f7eb2Smrg
2174627f7eb2Smrg default:
2175627f7eb2Smrg gfc_internal_error ("illegal OP in optimize_comparison");
2176627f7eb2Smrg break;
2177627f7eb2Smrg }
2178627f7eb2Smrg
2179627f7eb2Smrg /* Replace the expression by a constant expression. The typespec
2180627f7eb2Smrg and where remains the way it is. */
2181627f7eb2Smrg free (op1);
2182627f7eb2Smrg free (op2);
2183627f7eb2Smrg e->expr_type = EXPR_CONSTANT;
2184627f7eb2Smrg e->value.logical = result;
2185627f7eb2Smrg return true;
2186627f7eb2Smrg }
2187627f7eb2Smrg }
2188627f7eb2Smrg
2189627f7eb2Smrg return change;
2190627f7eb2Smrg }
2191627f7eb2Smrg
2192627f7eb2Smrg /* Optimize a trim function by replacing it with an equivalent substring
2193627f7eb2Smrg involving a call to len_trim. This only works for expressions where
2194627f7eb2Smrg variables are trimmed. Return true if anything was modified. */
2195627f7eb2Smrg
2196627f7eb2Smrg static bool
optimize_trim(gfc_expr * e)2197627f7eb2Smrg optimize_trim (gfc_expr *e)
2198627f7eb2Smrg {
2199627f7eb2Smrg gfc_expr *a;
2200627f7eb2Smrg gfc_ref *ref;
2201627f7eb2Smrg gfc_expr *fcn;
2202627f7eb2Smrg gfc_ref **rr = NULL;
2203627f7eb2Smrg
2204627f7eb2Smrg /* Don't do this optimization within an argument list, because
2205627f7eb2Smrg otherwise aliasing issues may occur. */
2206627f7eb2Smrg
2207627f7eb2Smrg if (count_arglist != 1)
2208627f7eb2Smrg return false;
2209627f7eb2Smrg
2210627f7eb2Smrg if (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_FUNCTION
2211627f7eb2Smrg || e->value.function.isym == NULL
2212627f7eb2Smrg || e->value.function.isym->id != GFC_ISYM_TRIM)
2213627f7eb2Smrg return false;
2214627f7eb2Smrg
2215627f7eb2Smrg a = e->value.function.actual->expr;
2216627f7eb2Smrg
2217627f7eb2Smrg if (a->expr_type != EXPR_VARIABLE)
2218627f7eb2Smrg return false;
2219627f7eb2Smrg
2220627f7eb2Smrg /* This would pessimize the idiom a = trim(a) for reallocatable strings. */
2221627f7eb2Smrg
2222627f7eb2Smrg if (a->symtree->n.sym->attr.allocatable)
2223627f7eb2Smrg return false;
2224627f7eb2Smrg
2225627f7eb2Smrg /* Follow all references to find the correct place to put the newly
2226627f7eb2Smrg created reference. FIXME: Also handle substring references and
2227627f7eb2Smrg array references. Array references cause strange regressions at
2228627f7eb2Smrg the moment. */
2229627f7eb2Smrg
2230627f7eb2Smrg if (a->ref)
2231627f7eb2Smrg {
2232627f7eb2Smrg for (rr = &(a->ref); *rr; rr = &((*rr)->next))
2233627f7eb2Smrg {
2234627f7eb2Smrg if ((*rr)->type == REF_SUBSTRING || (*rr)->type == REF_ARRAY)
2235627f7eb2Smrg return false;
2236627f7eb2Smrg }
2237627f7eb2Smrg }
2238627f7eb2Smrg
2239627f7eb2Smrg strip_function_call (e);
2240627f7eb2Smrg
2241627f7eb2Smrg if (e->ref == NULL)
2242627f7eb2Smrg rr = &(e->ref);
2243627f7eb2Smrg
2244627f7eb2Smrg /* Create the reference. */
2245627f7eb2Smrg
2246627f7eb2Smrg ref = gfc_get_ref ();
2247627f7eb2Smrg ref->type = REF_SUBSTRING;
2248627f7eb2Smrg
2249627f7eb2Smrg /* Set the start of the reference. */
2250627f7eb2Smrg
2251627f7eb2Smrg ref->u.ss.start = gfc_get_int_expr (gfc_charlen_int_kind, NULL, 1);
2252627f7eb2Smrg
2253627f7eb2Smrg /* Build the function call to len_trim(x, gfc_default_integer_kind). */
2254627f7eb2Smrg
2255627f7eb2Smrg fcn = get_len_trim_call (gfc_copy_expr (e), gfc_charlen_int_kind);
2256627f7eb2Smrg
2257627f7eb2Smrg /* Set the end of the reference to the call to len_trim. */
2258627f7eb2Smrg
2259627f7eb2Smrg ref->u.ss.end = fcn;
2260627f7eb2Smrg gcc_assert (rr != NULL && *rr == NULL);
2261627f7eb2Smrg *rr = ref;
2262627f7eb2Smrg return true;
2263627f7eb2Smrg }
2264627f7eb2Smrg
2265627f7eb2Smrg /* Optimize minloc(b), where b is rank 1 array, into
2266627f7eb2Smrg (/ minloc(b, dim=1) /), and similarly for maxloc,
2267627f7eb2Smrg as the latter forms are expanded inline. */
2268627f7eb2Smrg
2269627f7eb2Smrg static void
optimize_minmaxloc(gfc_expr ** e)2270627f7eb2Smrg optimize_minmaxloc (gfc_expr **e)
2271627f7eb2Smrg {
2272627f7eb2Smrg gfc_expr *fn = *e;
2273627f7eb2Smrg gfc_actual_arglist *a;
2274627f7eb2Smrg char *name, *p;
2275627f7eb2Smrg
2276627f7eb2Smrg if (fn->rank != 1
2277627f7eb2Smrg || fn->value.function.actual == NULL
2278627f7eb2Smrg || fn->value.function.actual->expr == NULL
2279627f7eb2Smrg || fn->value.function.actual->expr->rank != 1)
2280627f7eb2Smrg return;
2281627f7eb2Smrg
2282627f7eb2Smrg *e = gfc_get_array_expr (fn->ts.type, fn->ts.kind, &fn->where);
2283627f7eb2Smrg (*e)->shape = fn->shape;
2284627f7eb2Smrg fn->rank = 0;
2285627f7eb2Smrg fn->shape = NULL;
2286627f7eb2Smrg gfc_constructor_append_expr (&(*e)->value.constructor, fn, &fn->where);
2287627f7eb2Smrg
2288627f7eb2Smrg name = XALLOCAVEC (char, strlen (fn->value.function.name) + 1);
2289627f7eb2Smrg strcpy (name, fn->value.function.name);
2290627f7eb2Smrg p = strstr (name, "loc0");
2291627f7eb2Smrg p[3] = '1';
2292627f7eb2Smrg fn->value.function.name = gfc_get_string ("%s", name);
2293627f7eb2Smrg if (fn->value.function.actual->next)
2294627f7eb2Smrg {
2295627f7eb2Smrg a = fn->value.function.actual->next;
2296627f7eb2Smrg gcc_assert (a->expr == NULL);
2297627f7eb2Smrg }
2298627f7eb2Smrg else
2299627f7eb2Smrg {
2300627f7eb2Smrg a = gfc_get_actual_arglist ();
2301627f7eb2Smrg fn->value.function.actual->next = a;
2302627f7eb2Smrg }
2303627f7eb2Smrg a->expr = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
2304627f7eb2Smrg &fn->where);
2305627f7eb2Smrg mpz_set_ui (a->expr->value.integer, 1);
2306627f7eb2Smrg }
2307627f7eb2Smrg
2308627f7eb2Smrg /* Callback function for code checking that we do not pass a DO variable to an
2309627f7eb2Smrg INTENT(OUT) or INTENT(INOUT) dummy variable. */
2310627f7eb2Smrg
2311627f7eb2Smrg static int
doloop_code(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)2312627f7eb2Smrg doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
2313627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
2314627f7eb2Smrg {
2315627f7eb2Smrg gfc_code *co;
2316627f7eb2Smrg int i;
2317627f7eb2Smrg gfc_formal_arglist *f;
2318627f7eb2Smrg gfc_actual_arglist *a;
2319627f7eb2Smrg gfc_code *cl;
2320627f7eb2Smrg do_t loop, *lp;
2321627f7eb2Smrg bool seen_goto;
2322627f7eb2Smrg
2323627f7eb2Smrg co = *c;
2324627f7eb2Smrg
2325627f7eb2Smrg /* If the doloop_list grew, we have to truncate it here. */
2326627f7eb2Smrg
2327627f7eb2Smrg if ((unsigned) doloop_level < doloop_list.length())
2328627f7eb2Smrg doloop_list.truncate (doloop_level);
2329627f7eb2Smrg
2330627f7eb2Smrg seen_goto = false;
2331627f7eb2Smrg switch (co->op)
2332627f7eb2Smrg {
2333627f7eb2Smrg case EXEC_DO:
2334627f7eb2Smrg
2335627f7eb2Smrg if (co->ext.iterator && co->ext.iterator->var)
2336627f7eb2Smrg loop.c = co;
2337627f7eb2Smrg else
2338627f7eb2Smrg loop.c = NULL;
2339627f7eb2Smrg
2340627f7eb2Smrg loop.branch_level = if_level + select_level;
2341627f7eb2Smrg loop.seen_goto = false;
2342627f7eb2Smrg doloop_list.safe_push (loop);
2343627f7eb2Smrg break;
2344627f7eb2Smrg
2345627f7eb2Smrg /* If anything could transfer control away from a suspicious
2346627f7eb2Smrg subscript, make sure to set seen_goto in the current DO loop
2347627f7eb2Smrg (if any). */
2348627f7eb2Smrg case EXEC_GOTO:
2349627f7eb2Smrg case EXEC_EXIT:
2350627f7eb2Smrg case EXEC_STOP:
2351627f7eb2Smrg case EXEC_ERROR_STOP:
2352627f7eb2Smrg case EXEC_CYCLE:
2353627f7eb2Smrg seen_goto = true;
2354627f7eb2Smrg break;
2355627f7eb2Smrg
2356627f7eb2Smrg case EXEC_OPEN:
2357627f7eb2Smrg if (co->ext.open->err)
2358627f7eb2Smrg seen_goto = true;
2359627f7eb2Smrg break;
2360627f7eb2Smrg
2361627f7eb2Smrg case EXEC_CLOSE:
2362627f7eb2Smrg if (co->ext.close->err)
2363627f7eb2Smrg seen_goto = true;
2364627f7eb2Smrg break;
2365627f7eb2Smrg
2366627f7eb2Smrg case EXEC_BACKSPACE:
2367627f7eb2Smrg case EXEC_ENDFILE:
2368627f7eb2Smrg case EXEC_REWIND:
2369627f7eb2Smrg case EXEC_FLUSH:
2370627f7eb2Smrg
2371627f7eb2Smrg if (co->ext.filepos->err)
2372627f7eb2Smrg seen_goto = true;
2373627f7eb2Smrg break;
2374627f7eb2Smrg
2375627f7eb2Smrg case EXEC_INQUIRE:
2376627f7eb2Smrg if (co->ext.filepos->err)
2377627f7eb2Smrg seen_goto = true;
2378627f7eb2Smrg break;
2379627f7eb2Smrg
2380627f7eb2Smrg case EXEC_READ:
2381627f7eb2Smrg case EXEC_WRITE:
2382627f7eb2Smrg if (co->ext.dt->err || co->ext.dt->end || co->ext.dt->eor)
2383627f7eb2Smrg seen_goto = true;
2384627f7eb2Smrg break;
2385627f7eb2Smrg
2386627f7eb2Smrg case EXEC_WAIT:
2387627f7eb2Smrg if (co->ext.wait->err || co->ext.wait->end || co->ext.wait->eor)
2388627f7eb2Smrg loop.seen_goto = true;
2389627f7eb2Smrg break;
2390627f7eb2Smrg
2391627f7eb2Smrg case EXEC_CALL:
2392627f7eb2Smrg
2393627f7eb2Smrg if (co->resolved_sym == NULL)
2394627f7eb2Smrg break;
2395627f7eb2Smrg
2396627f7eb2Smrg f = gfc_sym_get_dummy_args (co->resolved_sym);
2397627f7eb2Smrg
2398627f7eb2Smrg /* Withot a formal arglist, there is only unknown INTENT,
2399627f7eb2Smrg which we don't check for. */
2400627f7eb2Smrg if (f == NULL)
2401627f7eb2Smrg break;
2402627f7eb2Smrg
2403627f7eb2Smrg a = co->ext.actual;
2404627f7eb2Smrg
2405627f7eb2Smrg while (a && f)
2406627f7eb2Smrg {
2407627f7eb2Smrg FOR_EACH_VEC_ELT (doloop_list, i, lp)
2408627f7eb2Smrg {
2409627f7eb2Smrg gfc_symbol *do_sym;
2410627f7eb2Smrg cl = lp->c;
2411627f7eb2Smrg
2412627f7eb2Smrg if (cl == NULL)
2413627f7eb2Smrg break;
2414627f7eb2Smrg
2415627f7eb2Smrg do_sym = cl->ext.iterator->var->symtree->n.sym;
2416627f7eb2Smrg
2417*4c3eb207Smrg if (a->expr && a->expr->symtree && f->sym
2418627f7eb2Smrg && a->expr->symtree->n.sym == do_sym)
2419627f7eb2Smrg {
2420627f7eb2Smrg if (f->sym->attr.intent == INTENT_OUT)
2421627f7eb2Smrg gfc_error_now ("Variable %qs at %L set to undefined "
2422627f7eb2Smrg "value inside loop beginning at %L as "
2423627f7eb2Smrg "INTENT(OUT) argument to subroutine %qs",
2424627f7eb2Smrg do_sym->name, &a->expr->where,
2425627f7eb2Smrg &(doloop_list[i].c->loc),
2426627f7eb2Smrg co->symtree->n.sym->name);
2427627f7eb2Smrg else if (f->sym->attr.intent == INTENT_INOUT)
2428627f7eb2Smrg gfc_error_now ("Variable %qs at %L not definable inside "
2429627f7eb2Smrg "loop beginning at %L as INTENT(INOUT) "
2430627f7eb2Smrg "argument to subroutine %qs",
2431627f7eb2Smrg do_sym->name, &a->expr->where,
2432627f7eb2Smrg &(doloop_list[i].c->loc),
2433627f7eb2Smrg co->symtree->n.sym->name);
2434627f7eb2Smrg }
2435627f7eb2Smrg }
2436627f7eb2Smrg a = a->next;
2437627f7eb2Smrg f = f->next;
2438627f7eb2Smrg }
2439627f7eb2Smrg break;
2440627f7eb2Smrg
2441627f7eb2Smrg default:
2442627f7eb2Smrg break;
2443627f7eb2Smrg }
2444627f7eb2Smrg if (seen_goto && doloop_level > 0)
2445627f7eb2Smrg doloop_list[doloop_level-1].seen_goto = true;
2446627f7eb2Smrg
2447627f7eb2Smrg return 0;
2448627f7eb2Smrg }
2449627f7eb2Smrg
2450627f7eb2Smrg /* Callback function to warn about different things within DO loops. */
2451627f7eb2Smrg
2452627f7eb2Smrg static int
do_function(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)2453627f7eb2Smrg do_function (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
2454627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
2455627f7eb2Smrg {
2456627f7eb2Smrg do_t *last;
2457627f7eb2Smrg
2458627f7eb2Smrg if (doloop_list.length () == 0)
2459627f7eb2Smrg return 0;
2460627f7eb2Smrg
2461627f7eb2Smrg if ((*e)->expr_type == EXPR_FUNCTION)
2462627f7eb2Smrg do_intent (e);
2463627f7eb2Smrg
2464627f7eb2Smrg last = &doloop_list.last();
2465627f7eb2Smrg if (last->seen_goto && !warn_do_subscript)
2466627f7eb2Smrg return 0;
2467627f7eb2Smrg
2468627f7eb2Smrg if ((*e)->expr_type == EXPR_VARIABLE)
2469627f7eb2Smrg do_subscript (e);
2470627f7eb2Smrg
2471627f7eb2Smrg return 0;
2472627f7eb2Smrg }
2473627f7eb2Smrg
2474627f7eb2Smrg typedef struct
2475627f7eb2Smrg {
2476627f7eb2Smrg gfc_symbol *sym;
2477627f7eb2Smrg mpz_t val;
2478627f7eb2Smrg } insert_index_t;
2479627f7eb2Smrg
2480627f7eb2Smrg /* Callback function - if the expression is the variable in data->sym,
2481627f7eb2Smrg replace it with a constant from data->val. */
2482627f7eb2Smrg
2483627f7eb2Smrg static int
callback_insert_index(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)2484627f7eb2Smrg callback_insert_index (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
2485627f7eb2Smrg void *data)
2486627f7eb2Smrg {
2487627f7eb2Smrg insert_index_t *d;
2488627f7eb2Smrg gfc_expr *ex, *n;
2489627f7eb2Smrg
2490627f7eb2Smrg ex = (*e);
2491627f7eb2Smrg if (ex->expr_type != EXPR_VARIABLE)
2492627f7eb2Smrg return 0;
2493627f7eb2Smrg
2494627f7eb2Smrg d = (insert_index_t *) data;
2495627f7eb2Smrg if (ex->symtree->n.sym != d->sym)
2496627f7eb2Smrg return 0;
2497627f7eb2Smrg
2498627f7eb2Smrg n = gfc_get_constant_expr (BT_INTEGER, ex->ts.kind, &ex->where);
2499627f7eb2Smrg mpz_set (n->value.integer, d->val);
2500627f7eb2Smrg
2501627f7eb2Smrg gfc_free_expr (ex);
2502627f7eb2Smrg *e = n;
2503627f7eb2Smrg return 0;
2504627f7eb2Smrg }
2505627f7eb2Smrg
2506627f7eb2Smrg /* In the expression e, replace occurrences of the variable sym with
2507627f7eb2Smrg val. If this results in a constant expression, return true and
2508627f7eb2Smrg return the value in ret. Return false if the expression already
2509627f7eb2Smrg is a constant. Caller has to clear ret in that case. */
2510627f7eb2Smrg
2511627f7eb2Smrg static bool
insert_index(gfc_expr * e,gfc_symbol * sym,mpz_t val,mpz_t ret)2512627f7eb2Smrg insert_index (gfc_expr *e, gfc_symbol *sym, mpz_t val, mpz_t ret)
2513627f7eb2Smrg {
2514627f7eb2Smrg gfc_expr *n;
2515627f7eb2Smrg insert_index_t data;
2516627f7eb2Smrg bool rc;
2517627f7eb2Smrg
2518627f7eb2Smrg if (e->expr_type == EXPR_CONSTANT)
2519627f7eb2Smrg return false;
2520627f7eb2Smrg
2521627f7eb2Smrg n = gfc_copy_expr (e);
2522627f7eb2Smrg data.sym = sym;
2523627f7eb2Smrg mpz_init_set (data.val, val);
2524627f7eb2Smrg gfc_expr_walker (&n, callback_insert_index, (void *) &data);
2525627f7eb2Smrg
2526627f7eb2Smrg /* Suppress errors here - we could get errors here such as an
2527627f7eb2Smrg out of bounds access for arrays, see PR 90563. */
2528627f7eb2Smrg gfc_push_suppress_errors ();
2529627f7eb2Smrg gfc_simplify_expr (n, 0);
2530627f7eb2Smrg gfc_pop_suppress_errors ();
2531627f7eb2Smrg
2532627f7eb2Smrg if (n->expr_type == EXPR_CONSTANT)
2533627f7eb2Smrg {
2534627f7eb2Smrg rc = true;
2535627f7eb2Smrg mpz_init_set (ret, n->value.integer);
2536627f7eb2Smrg }
2537627f7eb2Smrg else
2538627f7eb2Smrg rc = false;
2539627f7eb2Smrg
2540627f7eb2Smrg mpz_clear (data.val);
2541627f7eb2Smrg gfc_free_expr (n);
2542627f7eb2Smrg return rc;
2543627f7eb2Smrg
2544627f7eb2Smrg }
2545627f7eb2Smrg
2546627f7eb2Smrg /* Check array subscripts for possible out-of-bounds accesses in DO
2547627f7eb2Smrg loops with constant bounds. */
2548627f7eb2Smrg
2549627f7eb2Smrg static int
do_subscript(gfc_expr ** e)2550627f7eb2Smrg do_subscript (gfc_expr **e)
2551627f7eb2Smrg {
2552627f7eb2Smrg gfc_expr *v;
2553627f7eb2Smrg gfc_array_ref *ar;
2554627f7eb2Smrg gfc_ref *ref;
2555627f7eb2Smrg int i,j;
2556627f7eb2Smrg gfc_code *dl;
2557627f7eb2Smrg do_t *lp;
2558627f7eb2Smrg
2559627f7eb2Smrg v = *e;
2560627f7eb2Smrg /* Constants are already checked. */
2561627f7eb2Smrg if (v->expr_type == EXPR_CONSTANT)
2562627f7eb2Smrg return 0;
2563627f7eb2Smrg
2564627f7eb2Smrg /* Wrong warnings will be generated in an associate list. */
2565627f7eb2Smrg if (in_assoc_list)
2566627f7eb2Smrg return 0;
2567627f7eb2Smrg
2568627f7eb2Smrg /* We already warned about this. */
2569627f7eb2Smrg if (v->do_not_warn)
2570627f7eb2Smrg return 0;
2571627f7eb2Smrg
2572627f7eb2Smrg v->do_not_warn = 1;
2573627f7eb2Smrg
2574627f7eb2Smrg for (ref = v->ref; ref; ref = ref->next)
2575627f7eb2Smrg {
2576627f7eb2Smrg if (ref->type == REF_ARRAY && ref->u.ar.type == AR_ELEMENT)
2577627f7eb2Smrg {
2578627f7eb2Smrg ar = & ref->u.ar;
2579627f7eb2Smrg FOR_EACH_VEC_ELT (doloop_list, j, lp)
2580627f7eb2Smrg {
2581627f7eb2Smrg gfc_symbol *do_sym;
2582627f7eb2Smrg mpz_t do_start, do_step, do_end;
2583627f7eb2Smrg bool have_do_start, have_do_end;
2584627f7eb2Smrg bool error_not_proven;
2585627f7eb2Smrg int warn;
2586627f7eb2Smrg int sgn;
2587627f7eb2Smrg
2588627f7eb2Smrg dl = lp->c;
2589627f7eb2Smrg if (dl == NULL)
2590627f7eb2Smrg break;
2591627f7eb2Smrg
2592627f7eb2Smrg /* If we are within a branch, or a goto or equivalent
2593627f7eb2Smrg was seen in the DO loop before, then we cannot prove that
2594627f7eb2Smrg this expression is actually evaluated. Don't do anything
2595627f7eb2Smrg unless we want to see it all. */
2596627f7eb2Smrg error_not_proven = lp->seen_goto
2597627f7eb2Smrg || lp->branch_level < if_level + select_level;
2598627f7eb2Smrg
2599627f7eb2Smrg if (error_not_proven && !warn_do_subscript)
2600627f7eb2Smrg break;
2601627f7eb2Smrg
2602627f7eb2Smrg if (error_not_proven)
2603627f7eb2Smrg warn = OPT_Wdo_subscript;
2604627f7eb2Smrg else
2605627f7eb2Smrg warn = 0;
2606627f7eb2Smrg
2607627f7eb2Smrg do_sym = dl->ext.iterator->var->symtree->n.sym;
2608627f7eb2Smrg if (do_sym->ts.type != BT_INTEGER)
2609627f7eb2Smrg continue;
2610627f7eb2Smrg
2611627f7eb2Smrg /* If we do not know about the stepsize, the loop may be zero trip.
2612627f7eb2Smrg Do not warn in this case. */
2613627f7eb2Smrg
2614627f7eb2Smrg if (dl->ext.iterator->step->expr_type == EXPR_CONSTANT)
2615627f7eb2Smrg {
2616627f7eb2Smrg sgn = mpz_cmp_ui (dl->ext.iterator->step->value.integer, 0);
2617627f7eb2Smrg /* This can happen, but then the error has been
2618*4c3eb207Smrg reported previously. */
2619627f7eb2Smrg if (sgn == 0)
2620627f7eb2Smrg continue;
2621627f7eb2Smrg
2622627f7eb2Smrg mpz_init_set (do_step, dl->ext.iterator->step->value.integer);
2623627f7eb2Smrg }
2624627f7eb2Smrg
2625627f7eb2Smrg else
2626627f7eb2Smrg continue;
2627627f7eb2Smrg
2628627f7eb2Smrg if (dl->ext.iterator->start->expr_type == EXPR_CONSTANT)
2629627f7eb2Smrg {
2630627f7eb2Smrg have_do_start = true;
2631627f7eb2Smrg mpz_init_set (do_start, dl->ext.iterator->start->value.integer);
2632627f7eb2Smrg }
2633627f7eb2Smrg else
2634627f7eb2Smrg have_do_start = false;
2635627f7eb2Smrg
2636627f7eb2Smrg if (dl->ext.iterator->end->expr_type == EXPR_CONSTANT)
2637627f7eb2Smrg {
2638627f7eb2Smrg have_do_end = true;
2639627f7eb2Smrg mpz_init_set (do_end, dl->ext.iterator->end->value.integer);
2640627f7eb2Smrg }
2641627f7eb2Smrg else
2642627f7eb2Smrg have_do_end = false;
2643627f7eb2Smrg
2644627f7eb2Smrg if (!have_do_start && !have_do_end)
2645627f7eb2Smrg return 0;
2646627f7eb2Smrg
2647627f7eb2Smrg /* No warning inside a zero-trip loop. */
2648627f7eb2Smrg if (have_do_start && have_do_end)
2649627f7eb2Smrg {
2650627f7eb2Smrg int cmp;
2651627f7eb2Smrg
2652627f7eb2Smrg cmp = mpz_cmp (do_end, do_start);
2653627f7eb2Smrg if ((sgn > 0 && cmp < 0) || (sgn < 0 && cmp > 0))
2654627f7eb2Smrg break;
2655627f7eb2Smrg }
2656627f7eb2Smrg
2657627f7eb2Smrg /* May have to correct the end value if the step does not equal
2658627f7eb2Smrg one. */
2659627f7eb2Smrg if (have_do_start && have_do_end && mpz_cmp_ui (do_step, 1) != 0)
2660627f7eb2Smrg {
2661627f7eb2Smrg mpz_t diff, rem;
2662627f7eb2Smrg
2663627f7eb2Smrg mpz_init (diff);
2664627f7eb2Smrg mpz_init (rem);
2665627f7eb2Smrg mpz_sub (diff, do_end, do_start);
2666627f7eb2Smrg mpz_tdiv_r (rem, diff, do_step);
2667627f7eb2Smrg mpz_sub (do_end, do_end, rem);
2668627f7eb2Smrg mpz_clear (diff);
2669627f7eb2Smrg mpz_clear (rem);
2670627f7eb2Smrg }
2671627f7eb2Smrg
2672627f7eb2Smrg for (i = 0; i< ar->dimen; i++)
2673627f7eb2Smrg {
2674627f7eb2Smrg mpz_t val;
2675627f7eb2Smrg if (ar->dimen_type[i] == DIMEN_ELEMENT && have_do_start
2676627f7eb2Smrg && insert_index (ar->start[i], do_sym, do_start, val))
2677627f7eb2Smrg {
2678627f7eb2Smrg if (ar->as->lower[i]
2679627f7eb2Smrg && ar->as->lower[i]->expr_type == EXPR_CONSTANT
2680*4c3eb207Smrg && ar->as->lower[i]->ts.type == BT_INTEGER
2681627f7eb2Smrg && mpz_cmp (val, ar->as->lower[i]->value.integer) < 0)
2682627f7eb2Smrg gfc_warning (warn, "Array reference at %L out of bounds "
2683627f7eb2Smrg "(%ld < %ld) in loop beginning at %L",
2684627f7eb2Smrg &ar->start[i]->where, mpz_get_si (val),
2685627f7eb2Smrg mpz_get_si (ar->as->lower[i]->value.integer),
2686627f7eb2Smrg &doloop_list[j].c->loc);
2687627f7eb2Smrg
2688627f7eb2Smrg if (ar->as->upper[i]
2689627f7eb2Smrg && ar->as->upper[i]->expr_type == EXPR_CONSTANT
2690*4c3eb207Smrg && ar->as->upper[i]->ts.type == BT_INTEGER
2691627f7eb2Smrg && mpz_cmp (val, ar->as->upper[i]->value.integer) > 0)
2692627f7eb2Smrg gfc_warning (warn, "Array reference at %L out of bounds "
2693627f7eb2Smrg "(%ld > %ld) in loop beginning at %L",
2694627f7eb2Smrg &ar->start[i]->where, mpz_get_si (val),
2695627f7eb2Smrg mpz_get_si (ar->as->upper[i]->value.integer),
2696627f7eb2Smrg &doloop_list[j].c->loc);
2697627f7eb2Smrg
2698627f7eb2Smrg mpz_clear (val);
2699627f7eb2Smrg }
2700627f7eb2Smrg
2701627f7eb2Smrg if (ar->dimen_type[i] == DIMEN_ELEMENT && have_do_end
2702627f7eb2Smrg && insert_index (ar->start[i], do_sym, do_end, val))
2703627f7eb2Smrg {
2704627f7eb2Smrg if (ar->as->lower[i]
2705627f7eb2Smrg && ar->as->lower[i]->expr_type == EXPR_CONSTANT
2706*4c3eb207Smrg && ar->as->lower[i]->ts.type == BT_INTEGER
2707627f7eb2Smrg && mpz_cmp (val, ar->as->lower[i]->value.integer) < 0)
2708627f7eb2Smrg gfc_warning (warn, "Array reference at %L out of bounds "
2709627f7eb2Smrg "(%ld < %ld) in loop beginning at %L",
2710627f7eb2Smrg &ar->start[i]->where, mpz_get_si (val),
2711627f7eb2Smrg mpz_get_si (ar->as->lower[i]->value.integer),
2712627f7eb2Smrg &doloop_list[j].c->loc);
2713627f7eb2Smrg
2714627f7eb2Smrg if (ar->as->upper[i]
2715627f7eb2Smrg && ar->as->upper[i]->expr_type == EXPR_CONSTANT
2716*4c3eb207Smrg && ar->as->upper[i]->ts.type == BT_INTEGER
2717627f7eb2Smrg && mpz_cmp (val, ar->as->upper[i]->value.integer) > 0)
2718627f7eb2Smrg gfc_warning (warn, "Array reference at %L out of bounds "
2719627f7eb2Smrg "(%ld > %ld) in loop beginning at %L",
2720627f7eb2Smrg &ar->start[i]->where, mpz_get_si (val),
2721627f7eb2Smrg mpz_get_si (ar->as->upper[i]->value.integer),
2722627f7eb2Smrg &doloop_list[j].c->loc);
2723627f7eb2Smrg
2724627f7eb2Smrg mpz_clear (val);
2725627f7eb2Smrg }
2726627f7eb2Smrg }
2727627f7eb2Smrg }
2728627f7eb2Smrg }
2729627f7eb2Smrg }
2730627f7eb2Smrg return 0;
2731627f7eb2Smrg }
2732627f7eb2Smrg /* Function for functions checking that we do not pass a DO variable
2733627f7eb2Smrg to an INTENT(OUT) or INTENT(INOUT) dummy variable. */
2734627f7eb2Smrg
2735627f7eb2Smrg static int
do_intent(gfc_expr ** e)2736627f7eb2Smrg do_intent (gfc_expr **e)
2737627f7eb2Smrg {
2738627f7eb2Smrg gfc_formal_arglist *f;
2739627f7eb2Smrg gfc_actual_arglist *a;
2740627f7eb2Smrg gfc_expr *expr;
2741627f7eb2Smrg gfc_code *dl;
2742627f7eb2Smrg do_t *lp;
2743627f7eb2Smrg int i;
2744627f7eb2Smrg
2745627f7eb2Smrg expr = *e;
2746627f7eb2Smrg if (expr->expr_type != EXPR_FUNCTION)
2747627f7eb2Smrg return 0;
2748627f7eb2Smrg
2749627f7eb2Smrg /* Intrinsic functions don't modify their arguments. */
2750627f7eb2Smrg
2751627f7eb2Smrg if (expr->value.function.isym)
2752627f7eb2Smrg return 0;
2753627f7eb2Smrg
2754627f7eb2Smrg f = gfc_sym_get_dummy_args (expr->symtree->n.sym);
2755627f7eb2Smrg
2756627f7eb2Smrg /* Without a formal arglist, there is only unknown INTENT,
2757627f7eb2Smrg which we don't check for. */
2758627f7eb2Smrg if (f == NULL)
2759627f7eb2Smrg return 0;
2760627f7eb2Smrg
2761627f7eb2Smrg a = expr->value.function.actual;
2762627f7eb2Smrg
2763627f7eb2Smrg while (a && f)
2764627f7eb2Smrg {
2765627f7eb2Smrg FOR_EACH_VEC_ELT (doloop_list, i, lp)
2766627f7eb2Smrg {
2767627f7eb2Smrg gfc_symbol *do_sym;
2768627f7eb2Smrg dl = lp->c;
2769627f7eb2Smrg if (dl == NULL)
2770627f7eb2Smrg break;
2771627f7eb2Smrg
2772627f7eb2Smrg do_sym = dl->ext.iterator->var->symtree->n.sym;
2773627f7eb2Smrg
2774627f7eb2Smrg if (a->expr && a->expr->symtree
2775627f7eb2Smrg && a->expr->symtree->n.sym == do_sym)
2776627f7eb2Smrg {
2777627f7eb2Smrg if (f->sym->attr.intent == INTENT_OUT)
2778627f7eb2Smrg gfc_error_now ("Variable %qs at %L set to undefined value "
2779627f7eb2Smrg "inside loop beginning at %L as INTENT(OUT) "
2780627f7eb2Smrg "argument to function %qs", do_sym->name,
2781627f7eb2Smrg &a->expr->where, &doloop_list[i].c->loc,
2782627f7eb2Smrg expr->symtree->n.sym->name);
2783627f7eb2Smrg else if (f->sym->attr.intent == INTENT_INOUT)
2784627f7eb2Smrg gfc_error_now ("Variable %qs at %L not definable inside loop"
2785627f7eb2Smrg " beginning at %L as INTENT(INOUT) argument to"
2786627f7eb2Smrg " function %qs", do_sym->name,
2787627f7eb2Smrg &a->expr->where, &doloop_list[i].c->loc,
2788627f7eb2Smrg expr->symtree->n.sym->name);
2789627f7eb2Smrg }
2790627f7eb2Smrg }
2791627f7eb2Smrg a = a->next;
2792627f7eb2Smrg f = f->next;
2793627f7eb2Smrg }
2794627f7eb2Smrg
2795627f7eb2Smrg return 0;
2796627f7eb2Smrg }
2797627f7eb2Smrg
2798627f7eb2Smrg static void
doloop_warn(gfc_namespace * ns)2799627f7eb2Smrg doloop_warn (gfc_namespace *ns)
2800627f7eb2Smrg {
2801627f7eb2Smrg gfc_code_walker (&ns->code, doloop_code, do_function, NULL);
2802627f7eb2Smrg
2803627f7eb2Smrg for (ns = ns->contained; ns; ns = ns->sibling)
2804627f7eb2Smrg {
2805627f7eb2Smrg if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
2806627f7eb2Smrg doloop_warn (ns);
2807627f7eb2Smrg }
2808627f7eb2Smrg }
2809627f7eb2Smrg
2810627f7eb2Smrg /* This selction deals with inlining calls to MATMUL. */
2811627f7eb2Smrg
2812627f7eb2Smrg /* Replace calls to matmul outside of straight assignments with a temporary
2813627f7eb2Smrg variable so that later inlining will work. */
2814627f7eb2Smrg
2815627f7eb2Smrg static int
matmul_to_var_expr(gfc_expr ** ep,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)2816627f7eb2Smrg matmul_to_var_expr (gfc_expr **ep, int *walk_subtrees ATTRIBUTE_UNUSED,
2817627f7eb2Smrg void *data)
2818627f7eb2Smrg {
2819627f7eb2Smrg gfc_expr *e, *n;
2820627f7eb2Smrg bool *found = (bool *) data;
2821627f7eb2Smrg
2822627f7eb2Smrg e = *ep;
2823627f7eb2Smrg
2824627f7eb2Smrg if (e->expr_type != EXPR_FUNCTION
2825627f7eb2Smrg || e->value.function.isym == NULL
2826627f7eb2Smrg || e->value.function.isym->id != GFC_ISYM_MATMUL)
2827627f7eb2Smrg return 0;
2828627f7eb2Smrg
2829627f7eb2Smrg if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
2830627f7eb2Smrg || in_omp_atomic || in_where || in_assoc_list)
2831627f7eb2Smrg return 0;
2832627f7eb2Smrg
2833627f7eb2Smrg /* Check if this is already in the form c = matmul(a,b). */
2834627f7eb2Smrg
2835627f7eb2Smrg if ((*current_code)->expr2 == e)
2836627f7eb2Smrg return 0;
2837627f7eb2Smrg
2838627f7eb2Smrg n = create_var (e, "matmul");
2839627f7eb2Smrg
2840627f7eb2Smrg /* If create_var is unable to create a variable (for example if
2841627f7eb2Smrg -fno-realloc-lhs is in force with a variable that does not have bounds
2842627f7eb2Smrg known at compile-time), just return. */
2843627f7eb2Smrg
2844627f7eb2Smrg if (n == NULL)
2845627f7eb2Smrg return 0;
2846627f7eb2Smrg
2847627f7eb2Smrg *ep = n;
2848627f7eb2Smrg *found = true;
2849627f7eb2Smrg return 0;
2850627f7eb2Smrg }
2851627f7eb2Smrg
2852627f7eb2Smrg /* Set current_code and associated variables so that matmul_to_var_expr can
2853627f7eb2Smrg work. */
2854627f7eb2Smrg
2855627f7eb2Smrg static int
matmul_to_var_code(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)2856627f7eb2Smrg matmul_to_var_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
2857627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
2858627f7eb2Smrg {
2859627f7eb2Smrg if (current_code != c)
2860627f7eb2Smrg {
2861627f7eb2Smrg current_code = c;
2862627f7eb2Smrg inserted_block = NULL;
2863627f7eb2Smrg changed_statement = NULL;
2864627f7eb2Smrg }
2865627f7eb2Smrg
2866627f7eb2Smrg return 0;
2867627f7eb2Smrg }
2868627f7eb2Smrg
2869627f7eb2Smrg
2870627f7eb2Smrg /* Take a statement of the shape c = matmul(a,b) and create temporaries
2871627f7eb2Smrg for a and b if there is a dependency between the arguments and the
2872627f7eb2Smrg result variable or if a or b are the result of calculations that cannot
2873627f7eb2Smrg be handled by the inliner. */
2874627f7eb2Smrg
2875627f7eb2Smrg static int
matmul_temp_args(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)2876627f7eb2Smrg matmul_temp_args (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
2877627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
2878627f7eb2Smrg {
2879627f7eb2Smrg gfc_expr *expr1, *expr2;
2880627f7eb2Smrg gfc_code *co;
2881627f7eb2Smrg gfc_actual_arglist *a, *b;
2882627f7eb2Smrg bool a_tmp, b_tmp;
2883627f7eb2Smrg gfc_expr *matrix_a, *matrix_b;
2884627f7eb2Smrg bool conjg_a, conjg_b, transpose_a, transpose_b;
2885627f7eb2Smrg
2886627f7eb2Smrg co = *c;
2887627f7eb2Smrg
2888627f7eb2Smrg if (co->op != EXEC_ASSIGN)
2889627f7eb2Smrg return 0;
2890627f7eb2Smrg
2891627f7eb2Smrg if (forall_level > 0 || iterator_level > 0 || in_omp_workshare
2892627f7eb2Smrg || in_omp_atomic || in_where)
2893627f7eb2Smrg return 0;
2894627f7eb2Smrg
2895627f7eb2Smrg /* This has some duplication with inline_matmul_assign. This
2896627f7eb2Smrg is because the creation of temporary variables could still fail,
2897627f7eb2Smrg and inline_matmul_assign still needs to be able to handle these
2898627f7eb2Smrg cases. */
2899627f7eb2Smrg expr1 = co->expr1;
2900627f7eb2Smrg expr2 = co->expr2;
2901627f7eb2Smrg
2902627f7eb2Smrg if (expr2->expr_type != EXPR_FUNCTION
2903627f7eb2Smrg || expr2->value.function.isym == NULL
2904627f7eb2Smrg || expr2->value.function.isym->id != GFC_ISYM_MATMUL)
2905627f7eb2Smrg return 0;
2906627f7eb2Smrg
2907627f7eb2Smrg a_tmp = false;
2908627f7eb2Smrg a = expr2->value.function.actual;
2909627f7eb2Smrg matrix_a = check_conjg_transpose_variable (a->expr, &conjg_a, &transpose_a);
2910627f7eb2Smrg if (matrix_a != NULL)
2911627f7eb2Smrg {
2912627f7eb2Smrg if (matrix_a->expr_type == EXPR_VARIABLE
2913627f7eb2Smrg && (gfc_check_dependency (matrix_a, expr1, true)
2914*4c3eb207Smrg || gfc_has_dimen_vector_ref (matrix_a)))
2915627f7eb2Smrg a_tmp = true;
2916627f7eb2Smrg }
2917627f7eb2Smrg else
2918627f7eb2Smrg a_tmp = true;
2919627f7eb2Smrg
2920627f7eb2Smrg b_tmp = false;
2921627f7eb2Smrg b = a->next;
2922627f7eb2Smrg matrix_b = check_conjg_transpose_variable (b->expr, &conjg_b, &transpose_b);
2923627f7eb2Smrg if (matrix_b != NULL)
2924627f7eb2Smrg {
2925627f7eb2Smrg if (matrix_b->expr_type == EXPR_VARIABLE
2926627f7eb2Smrg && (gfc_check_dependency (matrix_b, expr1, true)
2927*4c3eb207Smrg || gfc_has_dimen_vector_ref (matrix_b)))
2928627f7eb2Smrg b_tmp = true;
2929627f7eb2Smrg }
2930627f7eb2Smrg else
2931627f7eb2Smrg b_tmp = true;
2932627f7eb2Smrg
2933627f7eb2Smrg if (!a_tmp && !b_tmp)
2934627f7eb2Smrg return 0;
2935627f7eb2Smrg
2936627f7eb2Smrg current_code = c;
2937627f7eb2Smrg inserted_block = NULL;
2938627f7eb2Smrg changed_statement = NULL;
2939627f7eb2Smrg if (a_tmp)
2940627f7eb2Smrg {
2941627f7eb2Smrg gfc_expr *at;
2942627f7eb2Smrg at = create_var (a->expr,"mma");
2943627f7eb2Smrg if (at)
2944627f7eb2Smrg a->expr = at;
2945627f7eb2Smrg }
2946627f7eb2Smrg if (b_tmp)
2947627f7eb2Smrg {
2948627f7eb2Smrg gfc_expr *bt;
2949627f7eb2Smrg bt = create_var (b->expr,"mmb");
2950627f7eb2Smrg if (bt)
2951627f7eb2Smrg b->expr = bt;
2952627f7eb2Smrg }
2953627f7eb2Smrg return 0;
2954627f7eb2Smrg }
2955627f7eb2Smrg
2956627f7eb2Smrg /* Auxiliary function to build and simplify an array inquiry function.
2957627f7eb2Smrg dim is zero-based. */
2958627f7eb2Smrg
2959627f7eb2Smrg static gfc_expr *
2960627f7eb2Smrg get_array_inq_function (gfc_isym_id id, gfc_expr *e, int dim, int okind = 0)
2961627f7eb2Smrg {
2962627f7eb2Smrg gfc_expr *fcn;
2963627f7eb2Smrg gfc_expr *dim_arg, *kind;
2964627f7eb2Smrg const char *name;
2965627f7eb2Smrg gfc_expr *ec;
2966627f7eb2Smrg
2967627f7eb2Smrg switch (id)
2968627f7eb2Smrg {
2969627f7eb2Smrg case GFC_ISYM_LBOUND:
2970627f7eb2Smrg name = "_gfortran_lbound";
2971627f7eb2Smrg break;
2972627f7eb2Smrg
2973627f7eb2Smrg case GFC_ISYM_UBOUND:
2974627f7eb2Smrg name = "_gfortran_ubound";
2975627f7eb2Smrg break;
2976627f7eb2Smrg
2977627f7eb2Smrg case GFC_ISYM_SIZE:
2978627f7eb2Smrg name = "_gfortran_size";
2979627f7eb2Smrg break;
2980627f7eb2Smrg
2981627f7eb2Smrg default:
2982627f7eb2Smrg gcc_unreachable ();
2983627f7eb2Smrg }
2984627f7eb2Smrg
2985627f7eb2Smrg dim_arg = gfc_get_int_expr (gfc_default_integer_kind, &e->where, dim);
2986627f7eb2Smrg if (okind != 0)
2987627f7eb2Smrg kind = gfc_get_int_expr (gfc_default_integer_kind, &e->where,
2988627f7eb2Smrg okind);
2989627f7eb2Smrg else
2990627f7eb2Smrg kind = gfc_get_int_expr (gfc_default_integer_kind, &e->where,
2991627f7eb2Smrg gfc_index_integer_kind);
2992627f7eb2Smrg
2993627f7eb2Smrg ec = gfc_copy_expr (e);
2994627f7eb2Smrg
2995627f7eb2Smrg /* No bounds checking, this will be done before the loops if -fcheck=bounds
2996627f7eb2Smrg is in effect. */
2997627f7eb2Smrg ec->no_bounds_check = 1;
2998627f7eb2Smrg fcn = gfc_build_intrinsic_call (current_ns, id, name, e->where, 3,
2999627f7eb2Smrg ec, dim_arg, kind);
3000627f7eb2Smrg gfc_simplify_expr (fcn, 0);
3001627f7eb2Smrg fcn->no_bounds_check = 1;
3002627f7eb2Smrg return fcn;
3003627f7eb2Smrg }
3004627f7eb2Smrg
3005627f7eb2Smrg /* Builds a logical expression. */
3006627f7eb2Smrg
3007627f7eb2Smrg static gfc_expr*
build_logical_expr(gfc_intrinsic_op op,gfc_expr * e1,gfc_expr * e2)3008627f7eb2Smrg build_logical_expr (gfc_intrinsic_op op, gfc_expr *e1, gfc_expr *e2)
3009627f7eb2Smrg {
3010627f7eb2Smrg gfc_typespec ts;
3011627f7eb2Smrg gfc_expr *res;
3012627f7eb2Smrg
3013627f7eb2Smrg ts.type = BT_LOGICAL;
3014627f7eb2Smrg ts.kind = gfc_default_logical_kind;
3015627f7eb2Smrg res = gfc_get_expr ();
3016627f7eb2Smrg res->where = e1->where;
3017627f7eb2Smrg res->expr_type = EXPR_OP;
3018627f7eb2Smrg res->value.op.op = op;
3019627f7eb2Smrg res->value.op.op1 = e1;
3020627f7eb2Smrg res->value.op.op2 = e2;
3021627f7eb2Smrg res->ts = ts;
3022627f7eb2Smrg
3023627f7eb2Smrg return res;
3024627f7eb2Smrg }
3025627f7eb2Smrg
3026627f7eb2Smrg
3027627f7eb2Smrg /* Return an operation of one two gfc_expr (one if e2 is NULL). This assumes
3028627f7eb2Smrg compatible typespecs. */
3029627f7eb2Smrg
3030627f7eb2Smrg static gfc_expr *
get_operand(gfc_intrinsic_op op,gfc_expr * e1,gfc_expr * e2)3031627f7eb2Smrg get_operand (gfc_intrinsic_op op, gfc_expr *e1, gfc_expr *e2)
3032627f7eb2Smrg {
3033627f7eb2Smrg gfc_expr *res;
3034627f7eb2Smrg
3035627f7eb2Smrg res = gfc_get_expr ();
3036627f7eb2Smrg res->ts = e1->ts;
3037627f7eb2Smrg res->where = e1->where;
3038627f7eb2Smrg res->expr_type = EXPR_OP;
3039627f7eb2Smrg res->value.op.op = op;
3040627f7eb2Smrg res->value.op.op1 = e1;
3041627f7eb2Smrg res->value.op.op2 = e2;
3042627f7eb2Smrg gfc_simplify_expr (res, 0);
3043627f7eb2Smrg return res;
3044627f7eb2Smrg }
3045627f7eb2Smrg
3046627f7eb2Smrg /* Generate the IF statement for a runtime check if we want to do inlining or
3047627f7eb2Smrg not - putting in the code for both branches and putting it into the syntax
3048627f7eb2Smrg tree is the caller's responsibility. For fixed array sizes, this should be
3049627f7eb2Smrg removed by DCE. Only called for rank-two matrices A and B. */
3050627f7eb2Smrg
3051627f7eb2Smrg static gfc_code *
inline_limit_check(gfc_expr * a,gfc_expr * b,int limit)3052627f7eb2Smrg inline_limit_check (gfc_expr *a, gfc_expr *b, int limit)
3053627f7eb2Smrg {
3054627f7eb2Smrg gfc_expr *inline_limit;
3055627f7eb2Smrg gfc_code *if_1, *if_2, *else_2;
3056627f7eb2Smrg gfc_expr *b2, *a2, *a1, *m1, *m2;
3057627f7eb2Smrg gfc_typespec ts;
3058627f7eb2Smrg gfc_expr *cond;
3059627f7eb2Smrg
3060627f7eb2Smrg /* Calculation is done in real to avoid integer overflow. */
3061627f7eb2Smrg
3062627f7eb2Smrg inline_limit = gfc_get_constant_expr (BT_REAL, gfc_default_real_kind,
3063627f7eb2Smrg &a->where);
3064627f7eb2Smrg mpfr_set_si (inline_limit->value.real, limit, GFC_RND_MODE);
3065627f7eb2Smrg mpfr_pow_ui (inline_limit->value.real, inline_limit->value.real, 3,
3066627f7eb2Smrg GFC_RND_MODE);
3067627f7eb2Smrg
3068627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, a, 1);
3069627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, a, 2);
3070627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, b, 2);
3071627f7eb2Smrg
3072627f7eb2Smrg gfc_clear_ts (&ts);
3073627f7eb2Smrg ts.type = BT_REAL;
3074627f7eb2Smrg ts.kind = gfc_default_real_kind;
3075627f7eb2Smrg gfc_convert_type_warn (a1, &ts, 2, 0);
3076627f7eb2Smrg gfc_convert_type_warn (a2, &ts, 2, 0);
3077627f7eb2Smrg gfc_convert_type_warn (b2, &ts, 2, 0);
3078627f7eb2Smrg
3079627f7eb2Smrg m1 = get_operand (INTRINSIC_TIMES, a1, a2);
3080627f7eb2Smrg m2 = get_operand (INTRINSIC_TIMES, m1, b2);
3081627f7eb2Smrg
3082627f7eb2Smrg cond = build_logical_expr (INTRINSIC_LE, m2, inline_limit);
3083627f7eb2Smrg gfc_simplify_expr (cond, 0);
3084627f7eb2Smrg
3085627f7eb2Smrg else_2 = XCNEW (gfc_code);
3086627f7eb2Smrg else_2->op = EXEC_IF;
3087627f7eb2Smrg else_2->loc = a->where;
3088627f7eb2Smrg
3089627f7eb2Smrg if_2 = XCNEW (gfc_code);
3090627f7eb2Smrg if_2->op = EXEC_IF;
3091627f7eb2Smrg if_2->expr1 = cond;
3092627f7eb2Smrg if_2->loc = a->where;
3093627f7eb2Smrg if_2->block = else_2;
3094627f7eb2Smrg
3095627f7eb2Smrg if_1 = XCNEW (gfc_code);
3096627f7eb2Smrg if_1->op = EXEC_IF;
3097627f7eb2Smrg if_1->block = if_2;
3098627f7eb2Smrg if_1->loc = a->where;
3099627f7eb2Smrg
3100627f7eb2Smrg return if_1;
3101627f7eb2Smrg }
3102627f7eb2Smrg
3103627f7eb2Smrg
3104627f7eb2Smrg /* Insert code to issue a runtime error if the expressions are not equal. */
3105627f7eb2Smrg
3106627f7eb2Smrg static gfc_code *
runtime_error_ne(gfc_expr * e1,gfc_expr * e2,const char * msg)3107627f7eb2Smrg runtime_error_ne (gfc_expr *e1, gfc_expr *e2, const char *msg)
3108627f7eb2Smrg {
3109627f7eb2Smrg gfc_expr *cond;
3110627f7eb2Smrg gfc_code *if_1, *if_2;
3111627f7eb2Smrg gfc_code *c;
3112627f7eb2Smrg gfc_actual_arglist *a1, *a2, *a3;
3113627f7eb2Smrg
3114627f7eb2Smrg gcc_assert (e1->where.lb);
3115627f7eb2Smrg /* Build the call to runtime_error. */
3116627f7eb2Smrg c = XCNEW (gfc_code);
3117627f7eb2Smrg c->op = EXEC_CALL;
3118627f7eb2Smrg c->loc = e1->where;
3119627f7eb2Smrg
3120627f7eb2Smrg /* Get a null-terminated message string. */
3121627f7eb2Smrg
3122627f7eb2Smrg a1 = gfc_get_actual_arglist ();
3123627f7eb2Smrg a1->expr = gfc_get_character_expr (gfc_default_character_kind, &e1->where,
3124627f7eb2Smrg msg, strlen(msg)+1);
3125627f7eb2Smrg c->ext.actual = a1;
3126627f7eb2Smrg
3127627f7eb2Smrg /* Pass the value of the first expression. */
3128627f7eb2Smrg a2 = gfc_get_actual_arglist ();
3129627f7eb2Smrg a2->expr = gfc_copy_expr (e1);
3130627f7eb2Smrg a1->next = a2;
3131627f7eb2Smrg
3132627f7eb2Smrg /* Pass the value of the second expression. */
3133627f7eb2Smrg a3 = gfc_get_actual_arglist ();
3134627f7eb2Smrg a3->expr = gfc_copy_expr (e2);
3135627f7eb2Smrg a2->next = a3;
3136627f7eb2Smrg
3137627f7eb2Smrg gfc_check_fe_runtime_error (c->ext.actual);
3138627f7eb2Smrg gfc_resolve_fe_runtime_error (c);
3139627f7eb2Smrg
3140627f7eb2Smrg if_2 = XCNEW (gfc_code);
3141627f7eb2Smrg if_2->op = EXEC_IF;
3142627f7eb2Smrg if_2->loc = e1->where;
3143627f7eb2Smrg if_2->next = c;
3144627f7eb2Smrg
3145627f7eb2Smrg if_1 = XCNEW (gfc_code);
3146627f7eb2Smrg if_1->op = EXEC_IF;
3147627f7eb2Smrg if_1->block = if_2;
3148627f7eb2Smrg if_1->loc = e1->where;
3149627f7eb2Smrg
3150627f7eb2Smrg cond = build_logical_expr (INTRINSIC_NE, e1, e2);
3151627f7eb2Smrg gfc_simplify_expr (cond, 0);
3152627f7eb2Smrg if_2->expr1 = cond;
3153627f7eb2Smrg
3154627f7eb2Smrg return if_1;
3155627f7eb2Smrg }
3156627f7eb2Smrg
3157627f7eb2Smrg /* Handle matrix reallocation. Caller is responsible to insert into
3158627f7eb2Smrg the code tree.
3159627f7eb2Smrg
3160627f7eb2Smrg For the two-dimensional case, build
3161627f7eb2Smrg
3162627f7eb2Smrg if (allocated(c)) then
3163627f7eb2Smrg if (size(c,1) /= size(a,1) .or. size(c,2) /= size(b,2)) then
3164627f7eb2Smrg deallocate(c)
3165627f7eb2Smrg allocate (c(size(a,1), size(b,2)))
3166627f7eb2Smrg end if
3167627f7eb2Smrg else
3168627f7eb2Smrg allocate (c(size(a,1),size(b,2)))
3169627f7eb2Smrg end if
3170627f7eb2Smrg
3171627f7eb2Smrg and for the other cases correspondingly.
3172627f7eb2Smrg */
3173627f7eb2Smrg
3174627f7eb2Smrg static gfc_code *
matmul_lhs_realloc(gfc_expr * c,gfc_expr * a,gfc_expr * b,enum matrix_case m_case)3175627f7eb2Smrg matmul_lhs_realloc (gfc_expr *c, gfc_expr *a, gfc_expr *b,
3176627f7eb2Smrg enum matrix_case m_case)
3177627f7eb2Smrg {
3178627f7eb2Smrg
3179627f7eb2Smrg gfc_expr *allocated, *alloc_expr;
3180627f7eb2Smrg gfc_code *if_alloc_1, *if_alloc_2, *if_size_1, *if_size_2;
3181627f7eb2Smrg gfc_code *else_alloc;
3182627f7eb2Smrg gfc_code *deallocate, *allocate1, *allocate_else;
3183627f7eb2Smrg gfc_array_ref *ar;
3184627f7eb2Smrg gfc_expr *cond, *ne1, *ne2;
3185627f7eb2Smrg
3186627f7eb2Smrg if (warn_realloc_lhs)
3187627f7eb2Smrg gfc_warning (OPT_Wrealloc_lhs,
3188627f7eb2Smrg "Code for reallocating the allocatable array at %L will "
3189627f7eb2Smrg "be added", &c->where);
3190627f7eb2Smrg
3191627f7eb2Smrg alloc_expr = gfc_copy_expr (c);
3192627f7eb2Smrg
3193627f7eb2Smrg ar = gfc_find_array_ref (alloc_expr);
3194627f7eb2Smrg gcc_assert (ar && ar->type == AR_FULL);
3195627f7eb2Smrg
3196627f7eb2Smrg /* c comes in as a full ref. Change it into a copy and make it into an
3197*4c3eb207Smrg element ref so it has the right form for ALLOCATE. In the same
3198627f7eb2Smrg switch statement, also generate the size comparison for the secod IF
3199627f7eb2Smrg statement. */
3200627f7eb2Smrg
3201627f7eb2Smrg ar->type = AR_ELEMENT;
3202627f7eb2Smrg
3203627f7eb2Smrg switch (m_case)
3204627f7eb2Smrg {
3205627f7eb2Smrg case A2B2:
3206627f7eb2Smrg ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 1);
3207627f7eb2Smrg ar->start[1] = get_array_inq_function (GFC_ISYM_SIZE, b, 2);
3208627f7eb2Smrg ne1 = build_logical_expr (INTRINSIC_NE,
3209627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 1),
3210627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, a, 1));
3211627f7eb2Smrg ne2 = build_logical_expr (INTRINSIC_NE,
3212627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 2),
3213627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, b, 2));
3214627f7eb2Smrg cond = build_logical_expr (INTRINSIC_OR, ne1, ne2);
3215627f7eb2Smrg break;
3216627f7eb2Smrg
3217627f7eb2Smrg case A2B2T:
3218627f7eb2Smrg ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 1);
3219627f7eb2Smrg ar->start[1] = get_array_inq_function (GFC_ISYM_SIZE, b, 1);
3220627f7eb2Smrg
3221627f7eb2Smrg ne1 = build_logical_expr (INTRINSIC_NE,
3222627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 1),
3223627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, a, 1));
3224627f7eb2Smrg ne2 = build_logical_expr (INTRINSIC_NE,
3225627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 2),
3226627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, b, 1));
3227627f7eb2Smrg cond = build_logical_expr (INTRINSIC_OR, ne1, ne2);
3228627f7eb2Smrg break;
3229627f7eb2Smrg
3230627f7eb2Smrg case A2TB2:
3231627f7eb2Smrg
3232627f7eb2Smrg ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 2);
3233627f7eb2Smrg ar->start[1] = get_array_inq_function (GFC_ISYM_SIZE, b, 2);
3234627f7eb2Smrg
3235627f7eb2Smrg ne1 = build_logical_expr (INTRINSIC_NE,
3236627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 1),
3237627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, a, 2));
3238627f7eb2Smrg ne2 = build_logical_expr (INTRINSIC_NE,
3239627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 2),
3240627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, b, 2));
3241627f7eb2Smrg cond = build_logical_expr (INTRINSIC_OR, ne1, ne2);
3242627f7eb2Smrg break;
3243627f7eb2Smrg
3244627f7eb2Smrg case A2B1:
3245627f7eb2Smrg ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 1);
3246627f7eb2Smrg cond = build_logical_expr (INTRINSIC_NE,
3247627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 1),
3248627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, a, 2));
3249627f7eb2Smrg break;
3250627f7eb2Smrg
3251627f7eb2Smrg case A1B2:
3252627f7eb2Smrg ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, b, 2);
3253627f7eb2Smrg cond = build_logical_expr (INTRINSIC_NE,
3254627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 1),
3255627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, b, 2));
3256627f7eb2Smrg break;
3257627f7eb2Smrg
3258627f7eb2Smrg case A2TB2T:
3259627f7eb2Smrg /* This can only happen for BLAS, we do not handle that case in
3260627f7eb2Smrg inline mamtul. */
3261627f7eb2Smrg ar->start[0] = get_array_inq_function (GFC_ISYM_SIZE, a, 2);
3262627f7eb2Smrg ar->start[1] = get_array_inq_function (GFC_ISYM_SIZE, b, 1);
3263627f7eb2Smrg
3264627f7eb2Smrg ne1 = build_logical_expr (INTRINSIC_NE,
3265627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 1),
3266627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, a, 2));
3267627f7eb2Smrg ne2 = build_logical_expr (INTRINSIC_NE,
3268627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, c, 2),
3269627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, b, 1));
3270627f7eb2Smrg
3271627f7eb2Smrg cond = build_logical_expr (INTRINSIC_OR, ne1, ne2);
3272627f7eb2Smrg break;
3273627f7eb2Smrg
3274627f7eb2Smrg default:
3275627f7eb2Smrg gcc_unreachable();
3276627f7eb2Smrg
3277627f7eb2Smrg }
3278627f7eb2Smrg
3279627f7eb2Smrg gfc_simplify_expr (cond, 0);
3280627f7eb2Smrg
3281627f7eb2Smrg /* We need two identical allocate statements in two
3282627f7eb2Smrg branches of the IF statement. */
3283627f7eb2Smrg
3284627f7eb2Smrg allocate1 = XCNEW (gfc_code);
3285627f7eb2Smrg allocate1->op = EXEC_ALLOCATE;
3286627f7eb2Smrg allocate1->ext.alloc.list = gfc_get_alloc ();
3287627f7eb2Smrg allocate1->loc = c->where;
3288627f7eb2Smrg allocate1->ext.alloc.list->expr = gfc_copy_expr (alloc_expr);
3289627f7eb2Smrg
3290627f7eb2Smrg allocate_else = XCNEW (gfc_code);
3291627f7eb2Smrg allocate_else->op = EXEC_ALLOCATE;
3292627f7eb2Smrg allocate_else->ext.alloc.list = gfc_get_alloc ();
3293627f7eb2Smrg allocate_else->loc = c->where;
3294627f7eb2Smrg allocate_else->ext.alloc.list->expr = alloc_expr;
3295627f7eb2Smrg
3296627f7eb2Smrg allocated = gfc_build_intrinsic_call (current_ns, GFC_ISYM_ALLOCATED,
3297627f7eb2Smrg "_gfortran_allocated", c->where,
3298627f7eb2Smrg 1, gfc_copy_expr (c));
3299627f7eb2Smrg
3300627f7eb2Smrg deallocate = XCNEW (gfc_code);
3301627f7eb2Smrg deallocate->op = EXEC_DEALLOCATE;
3302627f7eb2Smrg deallocate->ext.alloc.list = gfc_get_alloc ();
3303627f7eb2Smrg deallocate->ext.alloc.list->expr = gfc_copy_expr (c);
3304627f7eb2Smrg deallocate->next = allocate1;
3305627f7eb2Smrg deallocate->loc = c->where;
3306627f7eb2Smrg
3307627f7eb2Smrg if_size_2 = XCNEW (gfc_code);
3308627f7eb2Smrg if_size_2->op = EXEC_IF;
3309627f7eb2Smrg if_size_2->expr1 = cond;
3310627f7eb2Smrg if_size_2->loc = c->where;
3311627f7eb2Smrg if_size_2->next = deallocate;
3312627f7eb2Smrg
3313627f7eb2Smrg if_size_1 = XCNEW (gfc_code);
3314627f7eb2Smrg if_size_1->op = EXEC_IF;
3315627f7eb2Smrg if_size_1->block = if_size_2;
3316627f7eb2Smrg if_size_1->loc = c->where;
3317627f7eb2Smrg
3318627f7eb2Smrg else_alloc = XCNEW (gfc_code);
3319627f7eb2Smrg else_alloc->op = EXEC_IF;
3320627f7eb2Smrg else_alloc->loc = c->where;
3321627f7eb2Smrg else_alloc->next = allocate_else;
3322627f7eb2Smrg
3323627f7eb2Smrg if_alloc_2 = XCNEW (gfc_code);
3324627f7eb2Smrg if_alloc_2->op = EXEC_IF;
3325627f7eb2Smrg if_alloc_2->expr1 = allocated;
3326627f7eb2Smrg if_alloc_2->loc = c->where;
3327627f7eb2Smrg if_alloc_2->next = if_size_1;
3328627f7eb2Smrg if_alloc_2->block = else_alloc;
3329627f7eb2Smrg
3330627f7eb2Smrg if_alloc_1 = XCNEW (gfc_code);
3331627f7eb2Smrg if_alloc_1->op = EXEC_IF;
3332627f7eb2Smrg if_alloc_1->block = if_alloc_2;
3333627f7eb2Smrg if_alloc_1->loc = c->where;
3334627f7eb2Smrg
3335627f7eb2Smrg return if_alloc_1;
3336627f7eb2Smrg }
3337627f7eb2Smrg
3338627f7eb2Smrg /* Callback function for has_function_or_op. */
3339627f7eb2Smrg
3340627f7eb2Smrg static int
is_function_or_op(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)3341627f7eb2Smrg is_function_or_op (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
3342627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
3343627f7eb2Smrg {
3344627f7eb2Smrg if ((*e) == 0)
3345627f7eb2Smrg return 0;
3346627f7eb2Smrg else
3347627f7eb2Smrg return (*e)->expr_type == EXPR_FUNCTION
3348627f7eb2Smrg || (*e)->expr_type == EXPR_OP;
3349627f7eb2Smrg }
3350627f7eb2Smrg
3351627f7eb2Smrg /* Returns true if the expression contains a function. */
3352627f7eb2Smrg
3353627f7eb2Smrg static bool
has_function_or_op(gfc_expr ** e)3354627f7eb2Smrg has_function_or_op (gfc_expr **e)
3355627f7eb2Smrg {
3356627f7eb2Smrg if (e == NULL)
3357627f7eb2Smrg return false;
3358627f7eb2Smrg else
3359627f7eb2Smrg return gfc_expr_walker (e, is_function_or_op, NULL);
3360627f7eb2Smrg }
3361627f7eb2Smrg
3362627f7eb2Smrg /* Freeze (assign to a temporary variable) a single expression. */
3363627f7eb2Smrg
3364627f7eb2Smrg static void
freeze_expr(gfc_expr ** ep)3365627f7eb2Smrg freeze_expr (gfc_expr **ep)
3366627f7eb2Smrg {
3367627f7eb2Smrg gfc_expr *ne;
3368627f7eb2Smrg if (has_function_or_op (ep))
3369627f7eb2Smrg {
3370627f7eb2Smrg ne = create_var (*ep, "freeze");
3371627f7eb2Smrg *ep = ne;
3372627f7eb2Smrg }
3373627f7eb2Smrg }
3374627f7eb2Smrg
3375627f7eb2Smrg /* Go through an expression's references and assign them to temporary
3376627f7eb2Smrg variables if they contain functions. This is usually done prior to
3377627f7eb2Smrg front-end scalarization to avoid multiple invocations of functions. */
3378627f7eb2Smrg
3379627f7eb2Smrg static void
freeze_references(gfc_expr * e)3380627f7eb2Smrg freeze_references (gfc_expr *e)
3381627f7eb2Smrg {
3382627f7eb2Smrg gfc_ref *r;
3383627f7eb2Smrg gfc_array_ref *ar;
3384627f7eb2Smrg int i;
3385627f7eb2Smrg
3386627f7eb2Smrg for (r=e->ref; r; r=r->next)
3387627f7eb2Smrg {
3388627f7eb2Smrg if (r->type == REF_SUBSTRING)
3389627f7eb2Smrg {
3390627f7eb2Smrg if (r->u.ss.start != NULL)
3391627f7eb2Smrg freeze_expr (&r->u.ss.start);
3392627f7eb2Smrg
3393627f7eb2Smrg if (r->u.ss.end != NULL)
3394627f7eb2Smrg freeze_expr (&r->u.ss.end);
3395627f7eb2Smrg }
3396627f7eb2Smrg else if (r->type == REF_ARRAY)
3397627f7eb2Smrg {
3398627f7eb2Smrg ar = &r->u.ar;
3399627f7eb2Smrg switch (ar->type)
3400627f7eb2Smrg {
3401627f7eb2Smrg case AR_FULL:
3402627f7eb2Smrg break;
3403627f7eb2Smrg
3404627f7eb2Smrg case AR_SECTION:
3405627f7eb2Smrg for (i=0; i<ar->dimen; i++)
3406627f7eb2Smrg {
3407627f7eb2Smrg if (ar->dimen_type[i] == DIMEN_RANGE)
3408627f7eb2Smrg {
3409627f7eb2Smrg freeze_expr (&ar->start[i]);
3410627f7eb2Smrg freeze_expr (&ar->end[i]);
3411627f7eb2Smrg freeze_expr (&ar->stride[i]);
3412627f7eb2Smrg }
3413627f7eb2Smrg else if (ar->dimen_type[i] == DIMEN_ELEMENT)
3414627f7eb2Smrg {
3415627f7eb2Smrg freeze_expr (&ar->start[i]);
3416627f7eb2Smrg }
3417627f7eb2Smrg }
3418627f7eb2Smrg break;
3419627f7eb2Smrg
3420627f7eb2Smrg case AR_ELEMENT:
3421627f7eb2Smrg for (i=0; i<ar->dimen; i++)
3422627f7eb2Smrg freeze_expr (&ar->start[i]);
3423627f7eb2Smrg break;
3424627f7eb2Smrg
3425627f7eb2Smrg default:
3426627f7eb2Smrg break;
3427627f7eb2Smrg }
3428627f7eb2Smrg }
3429627f7eb2Smrg }
3430627f7eb2Smrg }
3431627f7eb2Smrg
3432627f7eb2Smrg /* Convert to gfc_index_integer_kind if needed, just do a copy otherwise. */
3433627f7eb2Smrg
3434627f7eb2Smrg static gfc_expr *
convert_to_index_kind(gfc_expr * e)3435627f7eb2Smrg convert_to_index_kind (gfc_expr *e)
3436627f7eb2Smrg {
3437627f7eb2Smrg gfc_expr *res;
3438627f7eb2Smrg
3439627f7eb2Smrg gcc_assert (e != NULL);
3440627f7eb2Smrg
3441627f7eb2Smrg res = gfc_copy_expr (e);
3442627f7eb2Smrg
3443627f7eb2Smrg gcc_assert (e->ts.type == BT_INTEGER);
3444627f7eb2Smrg
3445627f7eb2Smrg if (res->ts.kind != gfc_index_integer_kind)
3446627f7eb2Smrg {
3447627f7eb2Smrg gfc_typespec ts;
3448627f7eb2Smrg gfc_clear_ts (&ts);
3449627f7eb2Smrg ts.type = BT_INTEGER;
3450627f7eb2Smrg ts.kind = gfc_index_integer_kind;
3451627f7eb2Smrg
3452627f7eb2Smrg gfc_convert_type_warn (e, &ts, 2, 0);
3453627f7eb2Smrg }
3454627f7eb2Smrg
3455627f7eb2Smrg return res;
3456627f7eb2Smrg }
3457627f7eb2Smrg
3458627f7eb2Smrg /* Function to create a DO loop including creation of the
3459627f7eb2Smrg iteration variable. gfc_expr are copied.*/
3460627f7eb2Smrg
3461627f7eb2Smrg static gfc_code *
create_do_loop(gfc_expr * start,gfc_expr * end,gfc_expr * step,locus * where,gfc_namespace * ns,char * vname)3462627f7eb2Smrg create_do_loop (gfc_expr *start, gfc_expr *end, gfc_expr *step, locus *where,
3463627f7eb2Smrg gfc_namespace *ns, char *vname)
3464627f7eb2Smrg {
3465627f7eb2Smrg
3466627f7eb2Smrg char name[GFC_MAX_SYMBOL_LEN +1];
3467627f7eb2Smrg gfc_symtree *symtree;
3468627f7eb2Smrg gfc_symbol *symbol;
3469627f7eb2Smrg gfc_expr *i;
3470627f7eb2Smrg gfc_code *n, *n2;
3471627f7eb2Smrg
3472627f7eb2Smrg /* Create an expression for the iteration variable. */
3473627f7eb2Smrg if (vname)
3474627f7eb2Smrg sprintf (name, "__var_%d_do_%s", var_num++, vname);
3475627f7eb2Smrg else
3476627f7eb2Smrg sprintf (name, "__var_%d_do", var_num++);
3477627f7eb2Smrg
3478627f7eb2Smrg
3479627f7eb2Smrg if (gfc_get_sym_tree (name, ns, &symtree, false) != 0)
3480627f7eb2Smrg gcc_unreachable ();
3481627f7eb2Smrg
3482627f7eb2Smrg /* Create the loop variable. */
3483627f7eb2Smrg
3484627f7eb2Smrg symbol = symtree->n.sym;
3485627f7eb2Smrg symbol->ts.type = BT_INTEGER;
3486627f7eb2Smrg symbol->ts.kind = gfc_index_integer_kind;
3487627f7eb2Smrg symbol->attr.flavor = FL_VARIABLE;
3488627f7eb2Smrg symbol->attr.referenced = 1;
3489627f7eb2Smrg symbol->attr.dimension = 0;
3490627f7eb2Smrg symbol->attr.fe_temp = 1;
3491627f7eb2Smrg gfc_commit_symbol (symbol);
3492627f7eb2Smrg
3493627f7eb2Smrg i = gfc_get_expr ();
3494627f7eb2Smrg i->expr_type = EXPR_VARIABLE;
3495627f7eb2Smrg i->ts = symbol->ts;
3496627f7eb2Smrg i->rank = 0;
3497627f7eb2Smrg i->where = *where;
3498627f7eb2Smrg i->symtree = symtree;
3499627f7eb2Smrg
3500627f7eb2Smrg /* ... and the nested DO statements. */
3501627f7eb2Smrg n = XCNEW (gfc_code);
3502627f7eb2Smrg n->op = EXEC_DO;
3503627f7eb2Smrg n->loc = *where;
3504627f7eb2Smrg n->ext.iterator = gfc_get_iterator ();
3505627f7eb2Smrg n->ext.iterator->var = i;
3506627f7eb2Smrg n->ext.iterator->start = convert_to_index_kind (start);
3507627f7eb2Smrg n->ext.iterator->end = convert_to_index_kind (end);
3508627f7eb2Smrg if (step)
3509627f7eb2Smrg n->ext.iterator->step = convert_to_index_kind (step);
3510627f7eb2Smrg else
3511627f7eb2Smrg n->ext.iterator->step = gfc_get_int_expr (gfc_index_integer_kind,
3512627f7eb2Smrg where, 1);
3513627f7eb2Smrg
3514627f7eb2Smrg n2 = XCNEW (gfc_code);
3515627f7eb2Smrg n2->op = EXEC_DO;
3516627f7eb2Smrg n2->loc = *where;
3517627f7eb2Smrg n2->next = NULL;
3518627f7eb2Smrg n->block = n2;
3519627f7eb2Smrg return n;
3520627f7eb2Smrg }
3521627f7eb2Smrg
3522627f7eb2Smrg /* Get the upper bound of the DO loops for matmul along a dimension. This
3523627f7eb2Smrg is one-based. */
3524627f7eb2Smrg
3525627f7eb2Smrg static gfc_expr*
get_size_m1(gfc_expr * e,int dimen)3526627f7eb2Smrg get_size_m1 (gfc_expr *e, int dimen)
3527627f7eb2Smrg {
3528627f7eb2Smrg mpz_t size;
3529627f7eb2Smrg gfc_expr *res;
3530627f7eb2Smrg
3531627f7eb2Smrg if (gfc_array_dimen_size (e, dimen - 1, &size))
3532627f7eb2Smrg {
3533627f7eb2Smrg res = gfc_get_constant_expr (BT_INTEGER,
3534627f7eb2Smrg gfc_index_integer_kind, &e->where);
3535627f7eb2Smrg mpz_sub_ui (res->value.integer, size, 1);
3536627f7eb2Smrg mpz_clear (size);
3537627f7eb2Smrg }
3538627f7eb2Smrg else
3539627f7eb2Smrg {
3540627f7eb2Smrg res = get_operand (INTRINSIC_MINUS,
3541627f7eb2Smrg get_array_inq_function (GFC_ISYM_SIZE, e, dimen),
3542627f7eb2Smrg gfc_get_int_expr (gfc_index_integer_kind,
3543627f7eb2Smrg &e->where, 1));
3544627f7eb2Smrg gfc_simplify_expr (res, 0);
3545627f7eb2Smrg }
3546627f7eb2Smrg
3547627f7eb2Smrg return res;
3548627f7eb2Smrg }
3549627f7eb2Smrg
3550627f7eb2Smrg /* Function to return a scalarized expression. It is assumed that indices are
3551627f7eb2Smrg zero based to make generation of DO loops easier. A zero as index will
3552627f7eb2Smrg access the first element along a dimension. Single element references will
3553627f7eb2Smrg be skipped. A NULL as an expression will be replaced by a full reference.
3554627f7eb2Smrg This assumes that the index loops have gfc_index_integer_kind, and that all
3555627f7eb2Smrg references have been frozen. */
3556627f7eb2Smrg
3557627f7eb2Smrg static gfc_expr*
scalarized_expr(gfc_expr * e_in,gfc_expr ** index,int count_index)3558627f7eb2Smrg scalarized_expr (gfc_expr *e_in, gfc_expr **index, int count_index)
3559627f7eb2Smrg {
3560627f7eb2Smrg gfc_array_ref *ar;
3561627f7eb2Smrg int i;
3562627f7eb2Smrg int rank;
3563627f7eb2Smrg gfc_expr *e;
3564627f7eb2Smrg int i_index;
3565627f7eb2Smrg bool was_fullref;
3566627f7eb2Smrg
3567627f7eb2Smrg e = gfc_copy_expr(e_in);
3568627f7eb2Smrg
3569627f7eb2Smrg rank = e->rank;
3570627f7eb2Smrg
3571627f7eb2Smrg ar = gfc_find_array_ref (e);
3572627f7eb2Smrg
3573627f7eb2Smrg /* We scalarize count_index variables, reducing the rank by count_index. */
3574627f7eb2Smrg
3575627f7eb2Smrg e->rank = rank - count_index;
3576627f7eb2Smrg
3577627f7eb2Smrg was_fullref = ar->type == AR_FULL;
3578627f7eb2Smrg
3579627f7eb2Smrg if (e->rank == 0)
3580627f7eb2Smrg ar->type = AR_ELEMENT;
3581627f7eb2Smrg else
3582627f7eb2Smrg ar->type = AR_SECTION;
3583627f7eb2Smrg
3584627f7eb2Smrg /* Loop over the indices. For each index, create the expression
3585627f7eb2Smrg index * stride + lbound(e, dim). */
3586627f7eb2Smrg
3587627f7eb2Smrg i_index = 0;
3588627f7eb2Smrg for (i=0; i < ar->dimen; i++)
3589627f7eb2Smrg {
3590627f7eb2Smrg if (was_fullref || ar->dimen_type[i] == DIMEN_RANGE)
3591627f7eb2Smrg {
3592627f7eb2Smrg if (index[i_index] != NULL)
3593627f7eb2Smrg {
3594627f7eb2Smrg gfc_expr *lbound, *nindex;
3595627f7eb2Smrg gfc_expr *loopvar;
3596627f7eb2Smrg
3597627f7eb2Smrg loopvar = gfc_copy_expr (index[i_index]);
3598627f7eb2Smrg
3599627f7eb2Smrg if (ar->stride[i])
3600627f7eb2Smrg {
3601627f7eb2Smrg gfc_expr *tmp;
3602627f7eb2Smrg
3603627f7eb2Smrg tmp = gfc_copy_expr(ar->stride[i]);
3604627f7eb2Smrg if (tmp->ts.kind != gfc_index_integer_kind)
3605627f7eb2Smrg {
3606627f7eb2Smrg gfc_typespec ts;
3607627f7eb2Smrg gfc_clear_ts (&ts);
3608627f7eb2Smrg ts.type = BT_INTEGER;
3609627f7eb2Smrg ts.kind = gfc_index_integer_kind;
3610627f7eb2Smrg gfc_convert_type (tmp, &ts, 2);
3611627f7eb2Smrg }
3612627f7eb2Smrg nindex = get_operand (INTRINSIC_TIMES, loopvar, tmp);
3613627f7eb2Smrg }
3614627f7eb2Smrg else
3615627f7eb2Smrg nindex = loopvar;
3616627f7eb2Smrg
3617627f7eb2Smrg /* Calculate the lower bound of the expression. */
3618627f7eb2Smrg if (ar->start[i])
3619627f7eb2Smrg {
3620627f7eb2Smrg lbound = gfc_copy_expr (ar->start[i]);
3621627f7eb2Smrg if (lbound->ts.kind != gfc_index_integer_kind)
3622627f7eb2Smrg {
3623627f7eb2Smrg gfc_typespec ts;
3624627f7eb2Smrg gfc_clear_ts (&ts);
3625627f7eb2Smrg ts.type = BT_INTEGER;
3626627f7eb2Smrg ts.kind = gfc_index_integer_kind;
3627627f7eb2Smrg gfc_convert_type (lbound, &ts, 2);
3628627f7eb2Smrg
3629627f7eb2Smrg }
3630627f7eb2Smrg }
3631627f7eb2Smrg else
3632627f7eb2Smrg {
3633627f7eb2Smrg gfc_expr *lbound_e;
3634627f7eb2Smrg gfc_ref *ref;
3635627f7eb2Smrg
3636627f7eb2Smrg lbound_e = gfc_copy_expr (e_in);
3637627f7eb2Smrg
3638627f7eb2Smrg for (ref = lbound_e->ref; ref; ref = ref->next)
3639627f7eb2Smrg if (ref->type == REF_ARRAY
3640627f7eb2Smrg && (ref->u.ar.type == AR_FULL
3641627f7eb2Smrg || ref->u.ar.type == AR_SECTION))
3642627f7eb2Smrg break;
3643627f7eb2Smrg
3644627f7eb2Smrg if (ref->next)
3645627f7eb2Smrg {
3646627f7eb2Smrg gfc_free_ref_list (ref->next);
3647627f7eb2Smrg ref->next = NULL;
3648627f7eb2Smrg }
3649627f7eb2Smrg
3650627f7eb2Smrg if (!was_fullref)
3651627f7eb2Smrg {
3652627f7eb2Smrg /* Look at full individual sections, like a(:). The first index
3653627f7eb2Smrg is the lbound of a full ref. */
3654627f7eb2Smrg int j;
3655627f7eb2Smrg gfc_array_ref *ar;
3656627f7eb2Smrg int to;
3657627f7eb2Smrg
3658627f7eb2Smrg ar = &ref->u.ar;
3659627f7eb2Smrg
3660627f7eb2Smrg /* For assumed size, we need to keep around the final
3661627f7eb2Smrg reference in order not to get an error on resolution
3662627f7eb2Smrg below, and we cannot use AR_FULL. */
3663627f7eb2Smrg
3664627f7eb2Smrg if (ar->as->type == AS_ASSUMED_SIZE)
3665627f7eb2Smrg {
3666627f7eb2Smrg ar->type = AR_SECTION;
3667627f7eb2Smrg to = ar->dimen - 1;
3668627f7eb2Smrg }
3669627f7eb2Smrg else
3670627f7eb2Smrg {
3671627f7eb2Smrg to = ar->dimen;
3672627f7eb2Smrg ar->type = AR_FULL;
3673627f7eb2Smrg }
3674627f7eb2Smrg
3675627f7eb2Smrg for (j = 0; j < to; j++)
3676627f7eb2Smrg {
3677627f7eb2Smrg gfc_free_expr (ar->start[j]);
3678627f7eb2Smrg ar->start[j] = NULL;
3679627f7eb2Smrg gfc_free_expr (ar->end[j]);
3680627f7eb2Smrg ar->end[j] = NULL;
3681627f7eb2Smrg gfc_free_expr (ar->stride[j]);
3682627f7eb2Smrg ar->stride[j] = NULL;
3683627f7eb2Smrg }
3684627f7eb2Smrg
3685627f7eb2Smrg /* We have to get rid of the shape, if there is one. Do
3686627f7eb2Smrg so by freeing it and calling gfc_resolve to rebuild
3687627f7eb2Smrg it, if necessary. */
3688627f7eb2Smrg
3689627f7eb2Smrg if (lbound_e->shape)
3690627f7eb2Smrg gfc_free_shape (&(lbound_e->shape), lbound_e->rank);
3691627f7eb2Smrg
3692627f7eb2Smrg lbound_e->rank = ar->dimen;
3693627f7eb2Smrg gfc_resolve_expr (lbound_e);
3694627f7eb2Smrg }
3695627f7eb2Smrg lbound = get_array_inq_function (GFC_ISYM_LBOUND, lbound_e,
3696627f7eb2Smrg i + 1);
3697627f7eb2Smrg gfc_free_expr (lbound_e);
3698627f7eb2Smrg }
3699627f7eb2Smrg
3700627f7eb2Smrg ar->dimen_type[i] = DIMEN_ELEMENT;
3701627f7eb2Smrg
3702627f7eb2Smrg gfc_free_expr (ar->start[i]);
3703627f7eb2Smrg ar->start[i] = get_operand (INTRINSIC_PLUS, nindex, lbound);
3704627f7eb2Smrg
3705627f7eb2Smrg gfc_free_expr (ar->end[i]);
3706627f7eb2Smrg ar->end[i] = NULL;
3707627f7eb2Smrg gfc_free_expr (ar->stride[i]);
3708627f7eb2Smrg ar->stride[i] = NULL;
3709627f7eb2Smrg gfc_simplify_expr (ar->start[i], 0);
3710627f7eb2Smrg }
3711627f7eb2Smrg else if (was_fullref)
3712627f7eb2Smrg {
3713627f7eb2Smrg gfc_internal_error ("Scalarization using DIMEN_RANGE unimplemented");
3714627f7eb2Smrg }
3715627f7eb2Smrg i_index ++;
3716627f7eb2Smrg }
3717627f7eb2Smrg }
3718627f7eb2Smrg
3719627f7eb2Smrg /* Bounds checking will be done before the loops if -fcheck=bounds
3720627f7eb2Smrg is in effect. */
3721627f7eb2Smrg e->no_bounds_check = 1;
3722627f7eb2Smrg return e;
3723627f7eb2Smrg }
3724627f7eb2Smrg
3725627f7eb2Smrg /* Helper function to check for a dimen vector as subscript. */
3726627f7eb2Smrg
3727*4c3eb207Smrg bool
gfc_has_dimen_vector_ref(gfc_expr * e)3728*4c3eb207Smrg gfc_has_dimen_vector_ref (gfc_expr *e)
3729627f7eb2Smrg {
3730627f7eb2Smrg gfc_array_ref *ar;
3731627f7eb2Smrg int i;
3732627f7eb2Smrg
3733627f7eb2Smrg ar = gfc_find_array_ref (e);
3734627f7eb2Smrg gcc_assert (ar);
3735627f7eb2Smrg if (ar->type == AR_FULL)
3736627f7eb2Smrg return false;
3737627f7eb2Smrg
3738627f7eb2Smrg for (i=0; i<ar->dimen; i++)
3739627f7eb2Smrg if (ar->dimen_type[i] == DIMEN_VECTOR)
3740627f7eb2Smrg return true;
3741627f7eb2Smrg
3742627f7eb2Smrg return false;
3743627f7eb2Smrg }
3744627f7eb2Smrg
3745627f7eb2Smrg /* If handed an expression of the form
3746627f7eb2Smrg
3747627f7eb2Smrg TRANSPOSE(CONJG(A))
3748627f7eb2Smrg
3749627f7eb2Smrg check if A can be handled by matmul and return if there is an uneven number
3750627f7eb2Smrg of CONJG calls. Return a pointer to the array when everything is OK, NULL
3751627f7eb2Smrg otherwise. The caller has to check for the correct rank. */
3752627f7eb2Smrg
3753627f7eb2Smrg static gfc_expr*
check_conjg_transpose_variable(gfc_expr * e,bool * conjg,bool * transpose)3754627f7eb2Smrg check_conjg_transpose_variable (gfc_expr *e, bool *conjg, bool *transpose)
3755627f7eb2Smrg {
3756627f7eb2Smrg *conjg = false;
3757627f7eb2Smrg *transpose = false;
3758627f7eb2Smrg
3759627f7eb2Smrg do
3760627f7eb2Smrg {
3761627f7eb2Smrg if (e->expr_type == EXPR_VARIABLE)
3762627f7eb2Smrg {
3763627f7eb2Smrg gcc_assert (e->rank == 1 || e->rank == 2);
3764627f7eb2Smrg return e;
3765627f7eb2Smrg }
3766627f7eb2Smrg else if (e->expr_type == EXPR_FUNCTION)
3767627f7eb2Smrg {
3768627f7eb2Smrg if (e->value.function.isym == NULL)
3769627f7eb2Smrg return NULL;
3770627f7eb2Smrg
3771627f7eb2Smrg if (e->value.function.isym->id == GFC_ISYM_CONJG)
3772627f7eb2Smrg *conjg = !*conjg;
3773627f7eb2Smrg else if (e->value.function.isym->id == GFC_ISYM_TRANSPOSE)
3774627f7eb2Smrg *transpose = !*transpose;
3775627f7eb2Smrg else return NULL;
3776627f7eb2Smrg }
3777627f7eb2Smrg else
3778627f7eb2Smrg return NULL;
3779627f7eb2Smrg
3780627f7eb2Smrg e = e->value.function.actual->expr;
3781627f7eb2Smrg }
3782627f7eb2Smrg while(1);
3783627f7eb2Smrg
3784627f7eb2Smrg return NULL;
3785627f7eb2Smrg }
3786627f7eb2Smrg
3787627f7eb2Smrg /* Macros for unified error messages. */
3788627f7eb2Smrg
3789627f7eb2Smrg #define B_ERROR_1 _("Incorrect extent in argument B in MATMUL intrinsic in " \
3790627f7eb2Smrg "dimension 1: is %ld, should be %ld")
3791627f7eb2Smrg
3792627f7eb2Smrg #define C_ERROR_1 _("Array bound mismatch for dimension 1 of array " \
3793627f7eb2Smrg "(%ld/%ld)")
3794627f7eb2Smrg
3795627f7eb2Smrg #define C_ERROR_2 _("Array bound mismatch for dimension 2 of array " \
3796627f7eb2Smrg "(%ld/%ld)")
3797627f7eb2Smrg
3798627f7eb2Smrg
3799627f7eb2Smrg /* Inline assignments of the form c = matmul(a,b).
3800627f7eb2Smrg Handle only the cases currently where b and c are rank-two arrays.
3801627f7eb2Smrg
3802627f7eb2Smrg This basically translates the code to
3803627f7eb2Smrg
3804627f7eb2Smrg BLOCK
3805627f7eb2Smrg integer i,j,k
3806627f7eb2Smrg c = 0
3807627f7eb2Smrg do j=0, size(b,2)-1
3808627f7eb2Smrg do k=0, size(a, 2)-1
3809627f7eb2Smrg do i=0, size(a, 1)-1
3810627f7eb2Smrg c(i * stride(c,1) + lbound(c,1), j * stride(c,2) + lbound(c,2)) =
3811627f7eb2Smrg c(i * stride(c,1) + lbound(c,1), j * stride(c,2) + lbound(c,2)) +
3812627f7eb2Smrg a(i * stride(a,1) + lbound(a,1), k * stride(a,2) + lbound(a,2)) *
3813627f7eb2Smrg b(k * stride(b,1) + lbound(b,1), j * stride(b,2) + lbound(b,2))
3814627f7eb2Smrg end do
3815627f7eb2Smrg end do
3816627f7eb2Smrg end do
3817627f7eb2Smrg END BLOCK
3818627f7eb2Smrg
3819627f7eb2Smrg */
3820627f7eb2Smrg
3821627f7eb2Smrg static int
inline_matmul_assign(gfc_code ** c,int * walk_subtrees,void * data ATTRIBUTE_UNUSED)3822627f7eb2Smrg inline_matmul_assign (gfc_code **c, int *walk_subtrees,
3823627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
3824627f7eb2Smrg {
3825627f7eb2Smrg gfc_code *co = *c;
3826627f7eb2Smrg gfc_expr *expr1, *expr2;
3827627f7eb2Smrg gfc_expr *matrix_a, *matrix_b;
3828627f7eb2Smrg gfc_actual_arglist *a, *b;
3829627f7eb2Smrg gfc_code *do_1, *do_2, *do_3, *assign_zero, *assign_matmul;
3830627f7eb2Smrg gfc_expr *zero_e;
3831627f7eb2Smrg gfc_expr *u1, *u2, *u3;
3832627f7eb2Smrg gfc_expr *list[2];
3833627f7eb2Smrg gfc_expr *ascalar, *bscalar, *cscalar;
3834627f7eb2Smrg gfc_expr *mult;
3835627f7eb2Smrg gfc_expr *var_1, *var_2, *var_3;
3836627f7eb2Smrg gfc_expr *zero;
3837627f7eb2Smrg gfc_namespace *ns;
3838627f7eb2Smrg gfc_intrinsic_op op_times, op_plus;
3839627f7eb2Smrg enum matrix_case m_case;
3840627f7eb2Smrg int i;
3841627f7eb2Smrg gfc_code *if_limit = NULL;
3842627f7eb2Smrg gfc_code **next_code_point;
3843627f7eb2Smrg bool conjg_a, conjg_b, transpose_a, transpose_b;
3844627f7eb2Smrg bool realloc_c;
3845627f7eb2Smrg
3846627f7eb2Smrg if (co->op != EXEC_ASSIGN)
3847627f7eb2Smrg return 0;
3848627f7eb2Smrg
3849627f7eb2Smrg if (in_where || in_assoc_list)
3850627f7eb2Smrg return 0;
3851627f7eb2Smrg
3852627f7eb2Smrg /* The BLOCKS generated for the temporary variables and FORALL don't
3853627f7eb2Smrg mix. */
3854627f7eb2Smrg if (forall_level > 0)
3855627f7eb2Smrg return 0;
3856627f7eb2Smrg
3857627f7eb2Smrg /* For now don't do anything in OpenMP workshare, it confuses
3858627f7eb2Smrg its translation, which expects only the allowed statements in there.
3859627f7eb2Smrg We should figure out how to parallelize this eventually. */
3860627f7eb2Smrg if (in_omp_workshare || in_omp_atomic)
3861627f7eb2Smrg return 0;
3862627f7eb2Smrg
3863627f7eb2Smrg expr1 = co->expr1;
3864627f7eb2Smrg expr2 = co->expr2;
3865627f7eb2Smrg if (expr2->expr_type != EXPR_FUNCTION
3866627f7eb2Smrg || expr2->value.function.isym == NULL
3867627f7eb2Smrg || expr2->value.function.isym->id != GFC_ISYM_MATMUL)
3868627f7eb2Smrg return 0;
3869627f7eb2Smrg
3870627f7eb2Smrg current_code = c;
3871627f7eb2Smrg inserted_block = NULL;
3872627f7eb2Smrg changed_statement = NULL;
3873627f7eb2Smrg
3874627f7eb2Smrg a = expr2->value.function.actual;
3875627f7eb2Smrg matrix_a = check_conjg_transpose_variable (a->expr, &conjg_a, &transpose_a);
3876627f7eb2Smrg if (matrix_a == NULL)
3877627f7eb2Smrg return 0;
3878627f7eb2Smrg
3879627f7eb2Smrg b = a->next;
3880627f7eb2Smrg matrix_b = check_conjg_transpose_variable (b->expr, &conjg_b, &transpose_b);
3881627f7eb2Smrg if (matrix_b == NULL)
3882627f7eb2Smrg return 0;
3883627f7eb2Smrg
3884*4c3eb207Smrg if (gfc_has_dimen_vector_ref (expr1) || gfc_has_dimen_vector_ref (matrix_a)
3885*4c3eb207Smrg || gfc_has_dimen_vector_ref (matrix_b))
3886627f7eb2Smrg return 0;
3887627f7eb2Smrg
3888627f7eb2Smrg /* We do not handle data dependencies yet. */
3889627f7eb2Smrg if (gfc_check_dependency (expr1, matrix_a, true)
3890627f7eb2Smrg || gfc_check_dependency (expr1, matrix_b, true))
3891627f7eb2Smrg return 0;
3892627f7eb2Smrg
3893627f7eb2Smrg m_case = none;
3894627f7eb2Smrg if (matrix_a->rank == 2)
3895627f7eb2Smrg {
3896627f7eb2Smrg if (transpose_a)
3897627f7eb2Smrg {
3898627f7eb2Smrg if (matrix_b->rank == 2 && !transpose_b)
3899627f7eb2Smrg m_case = A2TB2;
3900627f7eb2Smrg }
3901627f7eb2Smrg else
3902627f7eb2Smrg {
3903627f7eb2Smrg if (matrix_b->rank == 1)
3904627f7eb2Smrg m_case = A2B1;
3905627f7eb2Smrg else /* matrix_b->rank == 2 */
3906627f7eb2Smrg {
3907627f7eb2Smrg if (transpose_b)
3908627f7eb2Smrg m_case = A2B2T;
3909627f7eb2Smrg else
3910627f7eb2Smrg m_case = A2B2;
3911627f7eb2Smrg }
3912627f7eb2Smrg }
3913627f7eb2Smrg }
3914627f7eb2Smrg else /* matrix_a->rank == 1 */
3915627f7eb2Smrg {
3916627f7eb2Smrg if (matrix_b->rank == 2)
3917627f7eb2Smrg {
3918627f7eb2Smrg if (!transpose_b)
3919627f7eb2Smrg m_case = A1B2;
3920627f7eb2Smrg }
3921627f7eb2Smrg }
3922627f7eb2Smrg
3923627f7eb2Smrg if (m_case == none)
3924627f7eb2Smrg return 0;
3925627f7eb2Smrg
3926*4c3eb207Smrg /* We only handle assignment to numeric or logical variables. */
3927*4c3eb207Smrg switch(expr1->ts.type)
3928*4c3eb207Smrg {
3929*4c3eb207Smrg case BT_INTEGER:
3930*4c3eb207Smrg case BT_LOGICAL:
3931*4c3eb207Smrg case BT_REAL:
3932*4c3eb207Smrg case BT_COMPLEX:
3933*4c3eb207Smrg break;
3934*4c3eb207Smrg
3935*4c3eb207Smrg default:
3936*4c3eb207Smrg return 0;
3937*4c3eb207Smrg }
3938*4c3eb207Smrg
3939627f7eb2Smrg ns = insert_block ();
3940627f7eb2Smrg
3941627f7eb2Smrg /* Assign the type of the zero expression for initializing the resulting
3942627f7eb2Smrg array, and the expression (+ and * for real, integer and complex;
3943627f7eb2Smrg .and. and .or for logical. */
3944627f7eb2Smrg
3945627f7eb2Smrg switch(expr1->ts.type)
3946627f7eb2Smrg {
3947627f7eb2Smrg case BT_INTEGER:
3948627f7eb2Smrg zero_e = gfc_get_int_expr (expr1->ts.kind, &expr1->where, 0);
3949627f7eb2Smrg op_times = INTRINSIC_TIMES;
3950627f7eb2Smrg op_plus = INTRINSIC_PLUS;
3951627f7eb2Smrg break;
3952627f7eb2Smrg
3953627f7eb2Smrg case BT_LOGICAL:
3954627f7eb2Smrg op_times = INTRINSIC_AND;
3955627f7eb2Smrg op_plus = INTRINSIC_OR;
3956627f7eb2Smrg zero_e = gfc_get_logical_expr (expr1->ts.kind, &expr1->where,
3957627f7eb2Smrg 0);
3958627f7eb2Smrg break;
3959627f7eb2Smrg case BT_REAL:
3960627f7eb2Smrg zero_e = gfc_get_constant_expr (BT_REAL, expr1->ts.kind,
3961627f7eb2Smrg &expr1->where);
3962627f7eb2Smrg mpfr_set_si (zero_e->value.real, 0, GFC_RND_MODE);
3963627f7eb2Smrg op_times = INTRINSIC_TIMES;
3964627f7eb2Smrg op_plus = INTRINSIC_PLUS;
3965627f7eb2Smrg break;
3966627f7eb2Smrg
3967627f7eb2Smrg case BT_COMPLEX:
3968627f7eb2Smrg zero_e = gfc_get_constant_expr (BT_COMPLEX, expr1->ts.kind,
3969627f7eb2Smrg &expr1->where);
3970627f7eb2Smrg mpc_set_si_si (zero_e->value.complex, 0, 0, GFC_RND_MODE);
3971627f7eb2Smrg op_times = INTRINSIC_TIMES;
3972627f7eb2Smrg op_plus = INTRINSIC_PLUS;
3973627f7eb2Smrg
3974627f7eb2Smrg break;
3975627f7eb2Smrg
3976627f7eb2Smrg default:
3977627f7eb2Smrg gcc_unreachable();
3978627f7eb2Smrg }
3979627f7eb2Smrg
3980627f7eb2Smrg current_code = &ns->code;
3981627f7eb2Smrg
3982627f7eb2Smrg /* Freeze the references, keeping track of how many temporary variables were
3983627f7eb2Smrg created. */
3984627f7eb2Smrg n_vars = 0;
3985627f7eb2Smrg freeze_references (matrix_a);
3986627f7eb2Smrg freeze_references (matrix_b);
3987627f7eb2Smrg freeze_references (expr1);
3988627f7eb2Smrg
3989627f7eb2Smrg if (n_vars == 0)
3990627f7eb2Smrg next_code_point = current_code;
3991627f7eb2Smrg else
3992627f7eb2Smrg {
3993627f7eb2Smrg next_code_point = &ns->code;
3994627f7eb2Smrg for (i=0; i<n_vars; i++)
3995627f7eb2Smrg next_code_point = &(*next_code_point)->next;
3996627f7eb2Smrg }
3997627f7eb2Smrg
3998627f7eb2Smrg /* Take care of the inline flag. If the limit check evaluates to a
3999627f7eb2Smrg constant, dead code elimination will eliminate the unneeded branch. */
4000627f7eb2Smrg
4001627f7eb2Smrg if (flag_inline_matmul_limit > 0 && matrix_a->rank == 2
4002627f7eb2Smrg && matrix_b->rank == 2)
4003627f7eb2Smrg {
4004627f7eb2Smrg if_limit = inline_limit_check (matrix_a, matrix_b,
4005627f7eb2Smrg flag_inline_matmul_limit);
4006627f7eb2Smrg
4007627f7eb2Smrg /* Insert the original statement into the else branch. */
4008627f7eb2Smrg if_limit->block->block->next = co;
4009627f7eb2Smrg co->next = NULL;
4010627f7eb2Smrg
4011627f7eb2Smrg /* ... and the new ones go into the original one. */
4012627f7eb2Smrg *next_code_point = if_limit;
4013627f7eb2Smrg next_code_point = &if_limit->block->next;
4014627f7eb2Smrg }
4015627f7eb2Smrg
4016627f7eb2Smrg zero_e->no_bounds_check = 1;
4017627f7eb2Smrg
4018627f7eb2Smrg assign_zero = XCNEW (gfc_code);
4019627f7eb2Smrg assign_zero->op = EXEC_ASSIGN;
4020627f7eb2Smrg assign_zero->loc = co->loc;
4021627f7eb2Smrg assign_zero->expr1 = gfc_copy_expr (expr1);
4022627f7eb2Smrg assign_zero->expr1->no_bounds_check = 1;
4023627f7eb2Smrg assign_zero->expr2 = zero_e;
4024627f7eb2Smrg
4025627f7eb2Smrg realloc_c = flag_realloc_lhs && gfc_is_reallocatable_lhs (expr1);
4026627f7eb2Smrg
4027627f7eb2Smrg if (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
4028627f7eb2Smrg {
4029627f7eb2Smrg gfc_code *test;
4030627f7eb2Smrg gfc_expr *a2, *b1, *c1, *c2, *a1, *b2;
4031627f7eb2Smrg
4032627f7eb2Smrg switch (m_case)
4033627f7eb2Smrg {
4034627f7eb2Smrg case A2B1:
4035627f7eb2Smrg
4036627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4037627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4038627f7eb2Smrg test = runtime_error_ne (b1, a2, B_ERROR_1);
4039627f7eb2Smrg *next_code_point = test;
4040627f7eb2Smrg next_code_point = &test->next;
4041627f7eb2Smrg
4042627f7eb2Smrg if (!realloc_c)
4043627f7eb2Smrg {
4044627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4045627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4046627f7eb2Smrg test = runtime_error_ne (c1, a1, C_ERROR_1);
4047627f7eb2Smrg *next_code_point = test;
4048627f7eb2Smrg next_code_point = &test->next;
4049627f7eb2Smrg }
4050627f7eb2Smrg break;
4051627f7eb2Smrg
4052627f7eb2Smrg case A1B2:
4053627f7eb2Smrg
4054627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4055627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4056627f7eb2Smrg test = runtime_error_ne (b1, a1, B_ERROR_1);
4057627f7eb2Smrg *next_code_point = test;
4058627f7eb2Smrg next_code_point = &test->next;
4059627f7eb2Smrg
4060627f7eb2Smrg if (!realloc_c)
4061627f7eb2Smrg {
4062627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4063627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4064627f7eb2Smrg test = runtime_error_ne (c1, b2, C_ERROR_1);
4065627f7eb2Smrg *next_code_point = test;
4066627f7eb2Smrg next_code_point = &test->next;
4067627f7eb2Smrg }
4068627f7eb2Smrg break;
4069627f7eb2Smrg
4070627f7eb2Smrg case A2B2:
4071627f7eb2Smrg
4072627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4073627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4074627f7eb2Smrg test = runtime_error_ne (b1, a2, B_ERROR_1);
4075627f7eb2Smrg *next_code_point = test;
4076627f7eb2Smrg next_code_point = &test->next;
4077627f7eb2Smrg
4078627f7eb2Smrg if (!realloc_c)
4079627f7eb2Smrg {
4080627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4081627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4082627f7eb2Smrg test = runtime_error_ne (c1, a1, C_ERROR_1);
4083627f7eb2Smrg *next_code_point = test;
4084627f7eb2Smrg next_code_point = &test->next;
4085627f7eb2Smrg
4086627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
4087627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4088627f7eb2Smrg test = runtime_error_ne (c2, b2, C_ERROR_2);
4089627f7eb2Smrg *next_code_point = test;
4090627f7eb2Smrg next_code_point = &test->next;
4091627f7eb2Smrg }
4092627f7eb2Smrg break;
4093627f7eb2Smrg
4094627f7eb2Smrg case A2B2T:
4095627f7eb2Smrg
4096627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4097627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4098627f7eb2Smrg /* matrix_b is transposed, hence dimension 1 for the error message. */
4099627f7eb2Smrg test = runtime_error_ne (b2, a2, B_ERROR_1);
4100627f7eb2Smrg *next_code_point = test;
4101627f7eb2Smrg next_code_point = &test->next;
4102627f7eb2Smrg
4103627f7eb2Smrg if (!realloc_c)
4104627f7eb2Smrg {
4105627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4106627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4107627f7eb2Smrg test = runtime_error_ne (c1, a1, C_ERROR_1);
4108627f7eb2Smrg *next_code_point = test;
4109627f7eb2Smrg next_code_point = &test->next;
4110627f7eb2Smrg
4111627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
4112627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4113627f7eb2Smrg test = runtime_error_ne (c2, b1, C_ERROR_2);
4114627f7eb2Smrg *next_code_point = test;
4115627f7eb2Smrg next_code_point = &test->next;
4116627f7eb2Smrg }
4117627f7eb2Smrg break;
4118627f7eb2Smrg
4119627f7eb2Smrg case A2TB2:
4120627f7eb2Smrg
4121627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4122627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4123627f7eb2Smrg test = runtime_error_ne (b1, a1, B_ERROR_1);
4124627f7eb2Smrg *next_code_point = test;
4125627f7eb2Smrg next_code_point = &test->next;
4126627f7eb2Smrg
4127627f7eb2Smrg if (!realloc_c)
4128627f7eb2Smrg {
4129627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4130627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4131627f7eb2Smrg test = runtime_error_ne (c1, a2, C_ERROR_1);
4132627f7eb2Smrg *next_code_point = test;
4133627f7eb2Smrg next_code_point = &test->next;
4134627f7eb2Smrg
4135627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
4136627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4137627f7eb2Smrg test = runtime_error_ne (c2, b2, C_ERROR_2);
4138627f7eb2Smrg *next_code_point = test;
4139627f7eb2Smrg next_code_point = &test->next;
4140627f7eb2Smrg }
4141627f7eb2Smrg break;
4142627f7eb2Smrg
4143627f7eb2Smrg default:
4144627f7eb2Smrg gcc_unreachable ();
4145627f7eb2Smrg }
4146627f7eb2Smrg }
4147627f7eb2Smrg
4148627f7eb2Smrg /* Handle the reallocation, if needed. */
4149627f7eb2Smrg
4150627f7eb2Smrg if (realloc_c)
4151627f7eb2Smrg {
4152627f7eb2Smrg gfc_code *lhs_alloc;
4153627f7eb2Smrg
4154627f7eb2Smrg lhs_alloc = matmul_lhs_realloc (expr1, matrix_a, matrix_b, m_case);
4155627f7eb2Smrg
4156627f7eb2Smrg *next_code_point = lhs_alloc;
4157627f7eb2Smrg next_code_point = &lhs_alloc->next;
4158627f7eb2Smrg
4159627f7eb2Smrg }
4160627f7eb2Smrg
4161627f7eb2Smrg *next_code_point = assign_zero;
4162627f7eb2Smrg
4163627f7eb2Smrg zero = gfc_get_int_expr (gfc_index_integer_kind, &co->loc, 0);
4164627f7eb2Smrg
4165627f7eb2Smrg assign_matmul = XCNEW (gfc_code);
4166627f7eb2Smrg assign_matmul->op = EXEC_ASSIGN;
4167627f7eb2Smrg assign_matmul->loc = co->loc;
4168627f7eb2Smrg
4169627f7eb2Smrg /* Get the bounds for the loops, create them and create the scalarized
4170627f7eb2Smrg expressions. */
4171627f7eb2Smrg
4172627f7eb2Smrg switch (m_case)
4173627f7eb2Smrg {
4174627f7eb2Smrg case A2B2:
4175627f7eb2Smrg
4176627f7eb2Smrg u1 = get_size_m1 (matrix_b, 2);
4177627f7eb2Smrg u2 = get_size_m1 (matrix_a, 2);
4178627f7eb2Smrg u3 = get_size_m1 (matrix_a, 1);
4179627f7eb2Smrg
4180627f7eb2Smrg do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns);
4181627f7eb2Smrg do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns);
4182627f7eb2Smrg do_3 = create_do_loop (gfc_copy_expr (zero), u3, NULL, &co->loc, ns);
4183627f7eb2Smrg
4184627f7eb2Smrg do_1->block->next = do_2;
4185627f7eb2Smrg do_2->block->next = do_3;
4186627f7eb2Smrg do_3->block->next = assign_matmul;
4187627f7eb2Smrg
4188627f7eb2Smrg var_1 = do_1->ext.iterator->var;
4189627f7eb2Smrg var_2 = do_2->ext.iterator->var;
4190627f7eb2Smrg var_3 = do_3->ext.iterator->var;
4191627f7eb2Smrg
4192627f7eb2Smrg list[0] = var_3;
4193627f7eb2Smrg list[1] = var_1;
4194627f7eb2Smrg cscalar = scalarized_expr (co->expr1, list, 2);
4195627f7eb2Smrg
4196627f7eb2Smrg list[0] = var_3;
4197627f7eb2Smrg list[1] = var_2;
4198627f7eb2Smrg ascalar = scalarized_expr (matrix_a, list, 2);
4199627f7eb2Smrg
4200627f7eb2Smrg list[0] = var_2;
4201627f7eb2Smrg list[1] = var_1;
4202627f7eb2Smrg bscalar = scalarized_expr (matrix_b, list, 2);
4203627f7eb2Smrg
4204627f7eb2Smrg break;
4205627f7eb2Smrg
4206627f7eb2Smrg case A2B2T:
4207627f7eb2Smrg
4208627f7eb2Smrg u1 = get_size_m1 (matrix_b, 1);
4209627f7eb2Smrg u2 = get_size_m1 (matrix_a, 2);
4210627f7eb2Smrg u3 = get_size_m1 (matrix_a, 1);
4211627f7eb2Smrg
4212627f7eb2Smrg do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns);
4213627f7eb2Smrg do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns);
4214627f7eb2Smrg do_3 = create_do_loop (gfc_copy_expr (zero), u3, NULL, &co->loc, ns);
4215627f7eb2Smrg
4216627f7eb2Smrg do_1->block->next = do_2;
4217627f7eb2Smrg do_2->block->next = do_3;
4218627f7eb2Smrg do_3->block->next = assign_matmul;
4219627f7eb2Smrg
4220627f7eb2Smrg var_1 = do_1->ext.iterator->var;
4221627f7eb2Smrg var_2 = do_2->ext.iterator->var;
4222627f7eb2Smrg var_3 = do_3->ext.iterator->var;
4223627f7eb2Smrg
4224627f7eb2Smrg list[0] = var_3;
4225627f7eb2Smrg list[1] = var_1;
4226627f7eb2Smrg cscalar = scalarized_expr (co->expr1, list, 2);
4227627f7eb2Smrg
4228627f7eb2Smrg list[0] = var_3;
4229627f7eb2Smrg list[1] = var_2;
4230627f7eb2Smrg ascalar = scalarized_expr (matrix_a, list, 2);
4231627f7eb2Smrg
4232627f7eb2Smrg list[0] = var_1;
4233627f7eb2Smrg list[1] = var_2;
4234627f7eb2Smrg bscalar = scalarized_expr (matrix_b, list, 2);
4235627f7eb2Smrg
4236627f7eb2Smrg break;
4237627f7eb2Smrg
4238627f7eb2Smrg case A2TB2:
4239627f7eb2Smrg
4240627f7eb2Smrg u1 = get_size_m1 (matrix_a, 2);
4241627f7eb2Smrg u2 = get_size_m1 (matrix_b, 2);
4242627f7eb2Smrg u3 = get_size_m1 (matrix_a, 1);
4243627f7eb2Smrg
4244627f7eb2Smrg do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns);
4245627f7eb2Smrg do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns);
4246627f7eb2Smrg do_3 = create_do_loop (gfc_copy_expr (zero), u3, NULL, &co->loc, ns);
4247627f7eb2Smrg
4248627f7eb2Smrg do_1->block->next = do_2;
4249627f7eb2Smrg do_2->block->next = do_3;
4250627f7eb2Smrg do_3->block->next = assign_matmul;
4251627f7eb2Smrg
4252627f7eb2Smrg var_1 = do_1->ext.iterator->var;
4253627f7eb2Smrg var_2 = do_2->ext.iterator->var;
4254627f7eb2Smrg var_3 = do_3->ext.iterator->var;
4255627f7eb2Smrg
4256627f7eb2Smrg list[0] = var_1;
4257627f7eb2Smrg list[1] = var_2;
4258627f7eb2Smrg cscalar = scalarized_expr (co->expr1, list, 2);
4259627f7eb2Smrg
4260627f7eb2Smrg list[0] = var_3;
4261627f7eb2Smrg list[1] = var_1;
4262627f7eb2Smrg ascalar = scalarized_expr (matrix_a, list, 2);
4263627f7eb2Smrg
4264627f7eb2Smrg list[0] = var_3;
4265627f7eb2Smrg list[1] = var_2;
4266627f7eb2Smrg bscalar = scalarized_expr (matrix_b, list, 2);
4267627f7eb2Smrg
4268627f7eb2Smrg break;
4269627f7eb2Smrg
4270627f7eb2Smrg case A2B1:
4271627f7eb2Smrg u1 = get_size_m1 (matrix_b, 1);
4272627f7eb2Smrg u2 = get_size_m1 (matrix_a, 1);
4273627f7eb2Smrg
4274627f7eb2Smrg do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns);
4275627f7eb2Smrg do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns);
4276627f7eb2Smrg
4277627f7eb2Smrg do_1->block->next = do_2;
4278627f7eb2Smrg do_2->block->next = assign_matmul;
4279627f7eb2Smrg
4280627f7eb2Smrg var_1 = do_1->ext.iterator->var;
4281627f7eb2Smrg var_2 = do_2->ext.iterator->var;
4282627f7eb2Smrg
4283627f7eb2Smrg list[0] = var_2;
4284627f7eb2Smrg cscalar = scalarized_expr (co->expr1, list, 1);
4285627f7eb2Smrg
4286627f7eb2Smrg list[0] = var_2;
4287627f7eb2Smrg list[1] = var_1;
4288627f7eb2Smrg ascalar = scalarized_expr (matrix_a, list, 2);
4289627f7eb2Smrg
4290627f7eb2Smrg list[0] = var_1;
4291627f7eb2Smrg bscalar = scalarized_expr (matrix_b, list, 1);
4292627f7eb2Smrg
4293627f7eb2Smrg break;
4294627f7eb2Smrg
4295627f7eb2Smrg case A1B2:
4296627f7eb2Smrg u1 = get_size_m1 (matrix_b, 2);
4297627f7eb2Smrg u2 = get_size_m1 (matrix_a, 1);
4298627f7eb2Smrg
4299627f7eb2Smrg do_1 = create_do_loop (gfc_copy_expr (zero), u1, NULL, &co->loc, ns);
4300627f7eb2Smrg do_2 = create_do_loop (gfc_copy_expr (zero), u2, NULL, &co->loc, ns);
4301627f7eb2Smrg
4302627f7eb2Smrg do_1->block->next = do_2;
4303627f7eb2Smrg do_2->block->next = assign_matmul;
4304627f7eb2Smrg
4305627f7eb2Smrg var_1 = do_1->ext.iterator->var;
4306627f7eb2Smrg var_2 = do_2->ext.iterator->var;
4307627f7eb2Smrg
4308627f7eb2Smrg list[0] = var_1;
4309627f7eb2Smrg cscalar = scalarized_expr (co->expr1, list, 1);
4310627f7eb2Smrg
4311627f7eb2Smrg list[0] = var_2;
4312627f7eb2Smrg ascalar = scalarized_expr (matrix_a, list, 1);
4313627f7eb2Smrg
4314627f7eb2Smrg list[0] = var_2;
4315627f7eb2Smrg list[1] = var_1;
4316627f7eb2Smrg bscalar = scalarized_expr (matrix_b, list, 2);
4317627f7eb2Smrg
4318627f7eb2Smrg break;
4319627f7eb2Smrg
4320627f7eb2Smrg default:
4321627f7eb2Smrg gcc_unreachable();
4322627f7eb2Smrg }
4323627f7eb2Smrg
4324627f7eb2Smrg /* Build the conjg call around the variables. Set the typespec manually
4325627f7eb2Smrg because gfc_build_intrinsic_call sometimes gets this wrong. */
4326627f7eb2Smrg if (conjg_a)
4327627f7eb2Smrg {
4328627f7eb2Smrg gfc_typespec ts;
4329627f7eb2Smrg ts = matrix_a->ts;
4330627f7eb2Smrg ascalar = gfc_build_intrinsic_call (ns, GFC_ISYM_CONJG, "conjg",
4331627f7eb2Smrg matrix_a->where, 1, ascalar);
4332627f7eb2Smrg ascalar->ts = ts;
4333627f7eb2Smrg }
4334627f7eb2Smrg
4335627f7eb2Smrg if (conjg_b)
4336627f7eb2Smrg {
4337627f7eb2Smrg gfc_typespec ts;
4338627f7eb2Smrg ts = matrix_b->ts;
4339627f7eb2Smrg bscalar = gfc_build_intrinsic_call (ns, GFC_ISYM_CONJG, "conjg",
4340627f7eb2Smrg matrix_b->where, 1, bscalar);
4341627f7eb2Smrg bscalar->ts = ts;
4342627f7eb2Smrg }
4343627f7eb2Smrg /* First loop comes after the zero assignment. */
4344627f7eb2Smrg assign_zero->next = do_1;
4345627f7eb2Smrg
4346627f7eb2Smrg /* Build the assignment expression in the loop. */
4347627f7eb2Smrg assign_matmul->expr1 = gfc_copy_expr (cscalar);
4348627f7eb2Smrg
4349627f7eb2Smrg mult = get_operand (op_times, ascalar, bscalar);
4350627f7eb2Smrg assign_matmul->expr2 = get_operand (op_plus, cscalar, mult);
4351627f7eb2Smrg
4352627f7eb2Smrg /* If we don't want to keep the original statement around in
4353627f7eb2Smrg the else branch, we can free it. */
4354627f7eb2Smrg
4355627f7eb2Smrg if (if_limit == NULL)
4356627f7eb2Smrg gfc_free_statements(co);
4357627f7eb2Smrg else
4358627f7eb2Smrg co->next = NULL;
4359627f7eb2Smrg
4360627f7eb2Smrg gfc_free_expr (zero);
4361627f7eb2Smrg *walk_subtrees = 0;
4362627f7eb2Smrg return 0;
4363627f7eb2Smrg }
4364627f7eb2Smrg
4365627f7eb2Smrg /* Change matmul function calls in the form of
4366627f7eb2Smrg
4367627f7eb2Smrg c = matmul(a,b)
4368627f7eb2Smrg
4369627f7eb2Smrg to the corresponding call to a BLAS routine, if applicable. */
4370627f7eb2Smrg
4371627f7eb2Smrg static int
call_external_blas(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)4372627f7eb2Smrg call_external_blas (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
4373627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
4374627f7eb2Smrg {
4375627f7eb2Smrg gfc_code *co, *co_next;
4376627f7eb2Smrg gfc_expr *expr1, *expr2;
4377627f7eb2Smrg gfc_expr *matrix_a, *matrix_b;
4378627f7eb2Smrg gfc_code *if_limit = NULL;
4379627f7eb2Smrg gfc_actual_arglist *a, *b;
4380627f7eb2Smrg bool conjg_a, conjg_b, transpose_a, transpose_b;
4381627f7eb2Smrg gfc_code *call;
4382627f7eb2Smrg const char *blas_name;
4383627f7eb2Smrg const char *transa, *transb;
4384627f7eb2Smrg gfc_expr *c1, *c2, *b1;
4385627f7eb2Smrg gfc_actual_arglist *actual, *next;
4386627f7eb2Smrg bt type;
4387627f7eb2Smrg int kind;
4388627f7eb2Smrg enum matrix_case m_case;
4389627f7eb2Smrg bool realloc_c;
4390627f7eb2Smrg gfc_code **next_code_point;
4391627f7eb2Smrg
4392627f7eb2Smrg /* Many of the tests for inline matmul also apply here. */
4393627f7eb2Smrg
4394627f7eb2Smrg co = *c;
4395627f7eb2Smrg
4396627f7eb2Smrg if (co->op != EXEC_ASSIGN)
4397627f7eb2Smrg return 0;
4398627f7eb2Smrg
4399627f7eb2Smrg if (in_where || in_assoc_list)
4400627f7eb2Smrg return 0;
4401627f7eb2Smrg
4402627f7eb2Smrg /* The BLOCKS generated for the temporary variables and FORALL don't
4403627f7eb2Smrg mix. */
4404627f7eb2Smrg if (forall_level > 0)
4405627f7eb2Smrg return 0;
4406627f7eb2Smrg
4407627f7eb2Smrg /* For now don't do anything in OpenMP workshare, it confuses
4408627f7eb2Smrg its translation, which expects only the allowed statements in there. */
4409627f7eb2Smrg
4410627f7eb2Smrg if (in_omp_workshare || in_omp_atomic)
4411627f7eb2Smrg return 0;
4412627f7eb2Smrg
4413627f7eb2Smrg expr1 = co->expr1;
4414627f7eb2Smrg expr2 = co->expr2;
4415627f7eb2Smrg if (expr2->expr_type != EXPR_FUNCTION
4416627f7eb2Smrg || expr2->value.function.isym == NULL
4417627f7eb2Smrg || expr2->value.function.isym->id != GFC_ISYM_MATMUL)
4418627f7eb2Smrg return 0;
4419627f7eb2Smrg
4420627f7eb2Smrg type = expr2->ts.type;
4421627f7eb2Smrg kind = expr2->ts.kind;
4422627f7eb2Smrg
4423627f7eb2Smrg /* Guard against recursion. */
4424627f7eb2Smrg
4425627f7eb2Smrg if (expr2->external_blas)
4426627f7eb2Smrg return 0;
4427627f7eb2Smrg
4428627f7eb2Smrg if (type != expr1->ts.type || kind != expr1->ts.kind)
4429627f7eb2Smrg return 0;
4430627f7eb2Smrg
4431627f7eb2Smrg if (type == BT_REAL)
4432627f7eb2Smrg {
4433627f7eb2Smrg if (kind == 4)
4434627f7eb2Smrg blas_name = "sgemm";
4435627f7eb2Smrg else if (kind == 8)
4436627f7eb2Smrg blas_name = "dgemm";
4437627f7eb2Smrg else
4438627f7eb2Smrg return 0;
4439627f7eb2Smrg }
4440627f7eb2Smrg else if (type == BT_COMPLEX)
4441627f7eb2Smrg {
4442627f7eb2Smrg if (kind == 4)
4443627f7eb2Smrg blas_name = "cgemm";
4444627f7eb2Smrg else if (kind == 8)
4445627f7eb2Smrg blas_name = "zgemm";
4446627f7eb2Smrg else
4447627f7eb2Smrg return 0;
4448627f7eb2Smrg }
4449627f7eb2Smrg else
4450627f7eb2Smrg return 0;
4451627f7eb2Smrg
4452627f7eb2Smrg a = expr2->value.function.actual;
4453627f7eb2Smrg if (a->expr->rank != 2)
4454627f7eb2Smrg return 0;
4455627f7eb2Smrg
4456627f7eb2Smrg b = a->next;
4457627f7eb2Smrg if (b->expr->rank != 2)
4458627f7eb2Smrg return 0;
4459627f7eb2Smrg
4460627f7eb2Smrg matrix_a = check_conjg_transpose_variable (a->expr, &conjg_a, &transpose_a);
4461627f7eb2Smrg if (matrix_a == NULL)
4462627f7eb2Smrg return 0;
4463627f7eb2Smrg
4464627f7eb2Smrg if (transpose_a)
4465627f7eb2Smrg {
4466627f7eb2Smrg if (conjg_a)
4467627f7eb2Smrg transa = "C";
4468627f7eb2Smrg else
4469627f7eb2Smrg transa = "T";
4470627f7eb2Smrg }
4471627f7eb2Smrg else
4472627f7eb2Smrg transa = "N";
4473627f7eb2Smrg
4474627f7eb2Smrg matrix_b = check_conjg_transpose_variable (b->expr, &conjg_b, &transpose_b);
4475627f7eb2Smrg if (matrix_b == NULL)
4476627f7eb2Smrg return 0;
4477627f7eb2Smrg
4478627f7eb2Smrg if (transpose_b)
4479627f7eb2Smrg {
4480627f7eb2Smrg if (conjg_b)
4481627f7eb2Smrg transb = "C";
4482627f7eb2Smrg else
4483627f7eb2Smrg transb = "T";
4484627f7eb2Smrg }
4485627f7eb2Smrg else
4486627f7eb2Smrg transb = "N";
4487627f7eb2Smrg
4488627f7eb2Smrg if (transpose_a)
4489627f7eb2Smrg {
4490627f7eb2Smrg if (transpose_b)
4491627f7eb2Smrg m_case = A2TB2T;
4492627f7eb2Smrg else
4493627f7eb2Smrg m_case = A2TB2;
4494627f7eb2Smrg }
4495627f7eb2Smrg else
4496627f7eb2Smrg {
4497627f7eb2Smrg if (transpose_b)
4498627f7eb2Smrg m_case = A2B2T;
4499627f7eb2Smrg else
4500627f7eb2Smrg m_case = A2B2;
4501627f7eb2Smrg }
4502627f7eb2Smrg
4503627f7eb2Smrg current_code = c;
4504627f7eb2Smrg inserted_block = NULL;
4505627f7eb2Smrg changed_statement = NULL;
4506627f7eb2Smrg
4507627f7eb2Smrg expr2->external_blas = 1;
4508627f7eb2Smrg
4509627f7eb2Smrg /* We do not handle data dependencies yet. */
4510627f7eb2Smrg if (gfc_check_dependency (expr1, matrix_a, true)
4511627f7eb2Smrg || gfc_check_dependency (expr1, matrix_b, true))
4512627f7eb2Smrg return 0;
4513627f7eb2Smrg
4514627f7eb2Smrg /* Generate the if statement and hang it into the tree. */
4515627f7eb2Smrg if_limit = inline_limit_check (matrix_a, matrix_b, flag_blas_matmul_limit);
4516627f7eb2Smrg co_next = co->next;
4517627f7eb2Smrg (*current_code) = if_limit;
4518627f7eb2Smrg co->next = NULL;
4519627f7eb2Smrg if_limit->block->next = co;
4520627f7eb2Smrg
4521627f7eb2Smrg call = XCNEW (gfc_code);
4522627f7eb2Smrg call->loc = co->loc;
4523627f7eb2Smrg
4524627f7eb2Smrg /* Bounds checking - a bit simpler than for inlining since we only
4525627f7eb2Smrg have to take care of two-dimensional arrays here. */
4526627f7eb2Smrg
4527627f7eb2Smrg realloc_c = flag_realloc_lhs && gfc_is_reallocatable_lhs (expr1);
4528627f7eb2Smrg next_code_point = &(if_limit->block->block->next);
4529627f7eb2Smrg
4530627f7eb2Smrg if (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
4531627f7eb2Smrg {
4532627f7eb2Smrg gfc_code *test;
4533627f7eb2Smrg // gfc_expr *a2, *b1, *c1, *c2, *a1, *b2;
4534627f7eb2Smrg gfc_expr *c1, *a1, *c2, *b2, *a2;
4535627f7eb2Smrg switch (m_case)
4536627f7eb2Smrg {
4537627f7eb2Smrg case A2B2:
4538627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4539627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4540627f7eb2Smrg test = runtime_error_ne (b1, a2, B_ERROR_1);
4541627f7eb2Smrg *next_code_point = test;
4542627f7eb2Smrg next_code_point = &test->next;
4543627f7eb2Smrg
4544627f7eb2Smrg if (!realloc_c)
4545627f7eb2Smrg {
4546627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4547627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4548627f7eb2Smrg test = runtime_error_ne (c1, a1, C_ERROR_1);
4549627f7eb2Smrg *next_code_point = test;
4550627f7eb2Smrg next_code_point = &test->next;
4551627f7eb2Smrg
4552627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
4553627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4554627f7eb2Smrg test = runtime_error_ne (c2, b2, C_ERROR_2);
4555627f7eb2Smrg *next_code_point = test;
4556627f7eb2Smrg next_code_point = &test->next;
4557627f7eb2Smrg }
4558627f7eb2Smrg break;
4559627f7eb2Smrg
4560627f7eb2Smrg case A2B2T:
4561627f7eb2Smrg
4562627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4563627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4564627f7eb2Smrg /* matrix_b is transposed, hence dimension 1 for the error message. */
4565627f7eb2Smrg test = runtime_error_ne (b2, a2, B_ERROR_1);
4566627f7eb2Smrg *next_code_point = test;
4567627f7eb2Smrg next_code_point = &test->next;
4568627f7eb2Smrg
4569627f7eb2Smrg if (!realloc_c)
4570627f7eb2Smrg {
4571627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4572627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4573627f7eb2Smrg test = runtime_error_ne (c1, a1, C_ERROR_1);
4574627f7eb2Smrg *next_code_point = test;
4575627f7eb2Smrg next_code_point = &test->next;
4576627f7eb2Smrg
4577627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
4578627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4579627f7eb2Smrg test = runtime_error_ne (c2, b1, C_ERROR_2);
4580627f7eb2Smrg *next_code_point = test;
4581627f7eb2Smrg next_code_point = &test->next;
4582627f7eb2Smrg }
4583627f7eb2Smrg break;
4584627f7eb2Smrg
4585627f7eb2Smrg case A2TB2:
4586627f7eb2Smrg
4587627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4588627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4589627f7eb2Smrg test = runtime_error_ne (b1, a1, B_ERROR_1);
4590627f7eb2Smrg *next_code_point = test;
4591627f7eb2Smrg next_code_point = &test->next;
4592627f7eb2Smrg
4593627f7eb2Smrg if (!realloc_c)
4594627f7eb2Smrg {
4595627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4596627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4597627f7eb2Smrg test = runtime_error_ne (c1, a2, C_ERROR_1);
4598627f7eb2Smrg *next_code_point = test;
4599627f7eb2Smrg next_code_point = &test->next;
4600627f7eb2Smrg
4601627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
4602627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4603627f7eb2Smrg test = runtime_error_ne (c2, b2, C_ERROR_2);
4604627f7eb2Smrg *next_code_point = test;
4605627f7eb2Smrg next_code_point = &test->next;
4606627f7eb2Smrg }
4607627f7eb2Smrg break;
4608627f7eb2Smrg
4609627f7eb2Smrg case A2TB2T:
4610627f7eb2Smrg b2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 2);
4611627f7eb2Smrg a1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 1);
4612627f7eb2Smrg test = runtime_error_ne (b2, a1, B_ERROR_1);
4613627f7eb2Smrg *next_code_point = test;
4614627f7eb2Smrg next_code_point = &test->next;
4615627f7eb2Smrg
4616627f7eb2Smrg if (!realloc_c)
4617627f7eb2Smrg {
4618627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 1);
4619627f7eb2Smrg a2 = get_array_inq_function (GFC_ISYM_SIZE, matrix_a, 2);
4620627f7eb2Smrg test = runtime_error_ne (c1, a2, C_ERROR_1);
4621627f7eb2Smrg *next_code_point = test;
4622627f7eb2Smrg next_code_point = &test->next;
4623627f7eb2Smrg
4624627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, expr1, 2);
4625627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, matrix_b, 1);
4626627f7eb2Smrg test = runtime_error_ne (c2, b1, C_ERROR_2);
4627627f7eb2Smrg *next_code_point = test;
4628627f7eb2Smrg next_code_point = &test->next;
4629627f7eb2Smrg }
4630627f7eb2Smrg break;
4631627f7eb2Smrg
4632627f7eb2Smrg default:
4633627f7eb2Smrg gcc_unreachable ();
4634627f7eb2Smrg }
4635627f7eb2Smrg }
4636627f7eb2Smrg
4637627f7eb2Smrg /* Handle the reallocation, if needed. */
4638627f7eb2Smrg
4639627f7eb2Smrg if (realloc_c)
4640627f7eb2Smrg {
4641627f7eb2Smrg gfc_code *lhs_alloc;
4642627f7eb2Smrg
4643627f7eb2Smrg lhs_alloc = matmul_lhs_realloc (expr1, matrix_a, matrix_b, m_case);
4644627f7eb2Smrg *next_code_point = lhs_alloc;
4645627f7eb2Smrg next_code_point = &lhs_alloc->next;
4646627f7eb2Smrg }
4647627f7eb2Smrg
4648627f7eb2Smrg *next_code_point = call;
4649627f7eb2Smrg if_limit->next = co_next;
4650627f7eb2Smrg
4651627f7eb2Smrg /* Set up the BLAS call. */
4652627f7eb2Smrg
4653627f7eb2Smrg call->op = EXEC_CALL;
4654627f7eb2Smrg
4655627f7eb2Smrg gfc_get_sym_tree (blas_name, current_ns, &(call->symtree), true);
4656627f7eb2Smrg call->symtree->n.sym->attr.subroutine = 1;
4657627f7eb2Smrg call->symtree->n.sym->attr.procedure = 1;
4658627f7eb2Smrg call->symtree->n.sym->attr.flavor = FL_PROCEDURE;
4659627f7eb2Smrg call->resolved_sym = call->symtree->n.sym;
4660627f7eb2Smrg gfc_commit_symbol (call->resolved_sym);
4661627f7eb2Smrg
4662627f7eb2Smrg /* Argument TRANSA. */
4663627f7eb2Smrg next = gfc_get_actual_arglist ();
4664627f7eb2Smrg next->expr = gfc_get_character_expr (gfc_default_character_kind, &co->loc,
4665627f7eb2Smrg transa, 1);
4666627f7eb2Smrg
4667627f7eb2Smrg call->ext.actual = next;
4668627f7eb2Smrg
4669627f7eb2Smrg /* Argument TRANSB. */
4670627f7eb2Smrg actual = next;
4671627f7eb2Smrg next = gfc_get_actual_arglist ();
4672627f7eb2Smrg next->expr = gfc_get_character_expr (gfc_default_character_kind, &co->loc,
4673627f7eb2Smrg transb, 1);
4674627f7eb2Smrg actual->next = next;
4675627f7eb2Smrg
4676627f7eb2Smrg c1 = get_array_inq_function (GFC_ISYM_SIZE, gfc_copy_expr (a->expr), 1,
4677627f7eb2Smrg gfc_integer_4_kind);
4678627f7eb2Smrg c2 = get_array_inq_function (GFC_ISYM_SIZE, gfc_copy_expr (b->expr), 2,
4679627f7eb2Smrg gfc_integer_4_kind);
4680627f7eb2Smrg
4681627f7eb2Smrg b1 = get_array_inq_function (GFC_ISYM_SIZE, gfc_copy_expr (b->expr), 1,
4682627f7eb2Smrg gfc_integer_4_kind);
4683627f7eb2Smrg
4684627f7eb2Smrg /* Argument M. */
4685627f7eb2Smrg actual = next;
4686627f7eb2Smrg next = gfc_get_actual_arglist ();
4687627f7eb2Smrg next->expr = c1;
4688627f7eb2Smrg actual->next = next;
4689627f7eb2Smrg
4690627f7eb2Smrg /* Argument N. */
4691627f7eb2Smrg actual = next;
4692627f7eb2Smrg next = gfc_get_actual_arglist ();
4693627f7eb2Smrg next->expr = c2;
4694627f7eb2Smrg actual->next = next;
4695627f7eb2Smrg
4696627f7eb2Smrg /* Argument K. */
4697627f7eb2Smrg actual = next;
4698627f7eb2Smrg next = gfc_get_actual_arglist ();
4699627f7eb2Smrg next->expr = b1;
4700627f7eb2Smrg actual->next = next;
4701627f7eb2Smrg
4702627f7eb2Smrg /* Argument ALPHA - set to one. */
4703627f7eb2Smrg actual = next;
4704627f7eb2Smrg next = gfc_get_actual_arglist ();
4705627f7eb2Smrg next->expr = gfc_get_constant_expr (type, kind, &co->loc);
4706627f7eb2Smrg if (type == BT_REAL)
4707627f7eb2Smrg mpfr_set_ui (next->expr->value.real, 1, GFC_RND_MODE);
4708627f7eb2Smrg else
4709627f7eb2Smrg mpc_set_ui (next->expr->value.complex, 1, GFC_MPC_RND_MODE);
4710627f7eb2Smrg actual->next = next;
4711627f7eb2Smrg
4712627f7eb2Smrg /* Argument A. */
4713627f7eb2Smrg actual = next;
4714627f7eb2Smrg next = gfc_get_actual_arglist ();
4715627f7eb2Smrg next->expr = gfc_copy_expr (matrix_a);
4716627f7eb2Smrg actual->next = next;
4717627f7eb2Smrg
4718627f7eb2Smrg /* Argument LDA. */
4719627f7eb2Smrg actual = next;
4720627f7eb2Smrg next = gfc_get_actual_arglist ();
4721627f7eb2Smrg next->expr = get_array_inq_function (GFC_ISYM_SIZE, gfc_copy_expr (matrix_a),
4722627f7eb2Smrg 1, gfc_integer_4_kind);
4723627f7eb2Smrg actual->next = next;
4724627f7eb2Smrg
4725627f7eb2Smrg /* Argument B. */
4726627f7eb2Smrg actual = next;
4727627f7eb2Smrg next = gfc_get_actual_arglist ();
4728627f7eb2Smrg next->expr = gfc_copy_expr (matrix_b);
4729627f7eb2Smrg actual->next = next;
4730627f7eb2Smrg
4731627f7eb2Smrg /* Argument LDB. */
4732627f7eb2Smrg actual = next;
4733627f7eb2Smrg next = gfc_get_actual_arglist ();
4734627f7eb2Smrg next->expr = get_array_inq_function (GFC_ISYM_SIZE, gfc_copy_expr (matrix_b),
4735627f7eb2Smrg 1, gfc_integer_4_kind);
4736627f7eb2Smrg actual->next = next;
4737627f7eb2Smrg
4738627f7eb2Smrg /* Argument BETA - set to zero. */
4739627f7eb2Smrg actual = next;
4740627f7eb2Smrg next = gfc_get_actual_arglist ();
4741627f7eb2Smrg next->expr = gfc_get_constant_expr (type, kind, &co->loc);
4742627f7eb2Smrg if (type == BT_REAL)
4743627f7eb2Smrg mpfr_set_ui (next->expr->value.real, 0, GFC_RND_MODE);
4744627f7eb2Smrg else
4745627f7eb2Smrg mpc_set_ui (next->expr->value.complex, 0, GFC_MPC_RND_MODE);
4746627f7eb2Smrg actual->next = next;
4747627f7eb2Smrg
4748627f7eb2Smrg /* Argument C. */
4749627f7eb2Smrg
4750627f7eb2Smrg actual = next;
4751627f7eb2Smrg next = gfc_get_actual_arglist ();
4752627f7eb2Smrg next->expr = gfc_copy_expr (expr1);
4753627f7eb2Smrg actual->next = next;
4754627f7eb2Smrg
4755627f7eb2Smrg /* Argument LDC. */
4756627f7eb2Smrg actual = next;
4757627f7eb2Smrg next = gfc_get_actual_arglist ();
4758627f7eb2Smrg next->expr = get_array_inq_function (GFC_ISYM_SIZE, gfc_copy_expr (expr1),
4759627f7eb2Smrg 1, gfc_integer_4_kind);
4760627f7eb2Smrg actual->next = next;
4761627f7eb2Smrg
4762627f7eb2Smrg return 0;
4763627f7eb2Smrg }
4764627f7eb2Smrg
4765627f7eb2Smrg
4766627f7eb2Smrg /* Code for index interchange for loops which are grouped together in DO
4767627f7eb2Smrg CONCURRENT or FORALL statements. This is currently only applied if the
4768627f7eb2Smrg iterations are grouped together in a single statement.
4769627f7eb2Smrg
4770627f7eb2Smrg For this transformation, it is assumed that memory access in strides is
4771627f7eb2Smrg expensive, and that loops which access later indices (which access memory
4772627f7eb2Smrg in bigger strides) should be moved to the first loops.
4773627f7eb2Smrg
4774627f7eb2Smrg For this, a loop over all the statements is executed, counting the times
4775627f7eb2Smrg that the loop iteration values are accessed in each index. The loop
4776627f7eb2Smrg indices are then sorted to minimize access to later indices from inner
4777627f7eb2Smrg loops. */
4778627f7eb2Smrg
4779627f7eb2Smrg /* Type for holding index information. */
4780627f7eb2Smrg
4781627f7eb2Smrg typedef struct {
4782627f7eb2Smrg gfc_symbol *sym;
4783627f7eb2Smrg gfc_forall_iterator *fa;
4784627f7eb2Smrg int num;
4785627f7eb2Smrg int n[GFC_MAX_DIMENSIONS];
4786627f7eb2Smrg } ind_type;
4787627f7eb2Smrg
4788627f7eb2Smrg /* Callback function to determine if an expression is the
4789627f7eb2Smrg corresponding variable. */
4790627f7eb2Smrg
4791627f7eb2Smrg static int
has_var(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)4792627f7eb2Smrg has_var (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
4793627f7eb2Smrg {
4794627f7eb2Smrg gfc_expr *expr = *e;
4795627f7eb2Smrg gfc_symbol *sym;
4796627f7eb2Smrg
4797627f7eb2Smrg if (expr->expr_type != EXPR_VARIABLE)
4798627f7eb2Smrg return 0;
4799627f7eb2Smrg
4800627f7eb2Smrg sym = (gfc_symbol *) data;
4801627f7eb2Smrg return sym == expr->symtree->n.sym;
4802627f7eb2Smrg }
4803627f7eb2Smrg
4804627f7eb2Smrg /* Callback function to calculate the cost of a certain index. */
4805627f7eb2Smrg
4806627f7eb2Smrg static int
index_cost(gfc_expr ** e,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)4807627f7eb2Smrg index_cost (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
4808627f7eb2Smrg void *data)
4809627f7eb2Smrg {
4810627f7eb2Smrg ind_type *ind;
4811627f7eb2Smrg gfc_expr *expr;
4812627f7eb2Smrg gfc_array_ref *ar;
4813627f7eb2Smrg gfc_ref *ref;
4814627f7eb2Smrg int i,j;
4815627f7eb2Smrg
4816627f7eb2Smrg expr = *e;
4817627f7eb2Smrg if (expr->expr_type != EXPR_VARIABLE)
4818627f7eb2Smrg return 0;
4819627f7eb2Smrg
4820627f7eb2Smrg ar = NULL;
4821627f7eb2Smrg for (ref = expr->ref; ref; ref = ref->next)
4822627f7eb2Smrg {
4823627f7eb2Smrg if (ref->type == REF_ARRAY)
4824627f7eb2Smrg {
4825627f7eb2Smrg ar = &ref->u.ar;
4826627f7eb2Smrg break;
4827627f7eb2Smrg }
4828627f7eb2Smrg }
4829627f7eb2Smrg if (ar == NULL || ar->type != AR_ELEMENT)
4830627f7eb2Smrg return 0;
4831627f7eb2Smrg
4832627f7eb2Smrg ind = (ind_type *) data;
4833627f7eb2Smrg for (i = 0; i < ar->dimen; i++)
4834627f7eb2Smrg {
4835627f7eb2Smrg for (j=0; ind[j].sym != NULL; j++)
4836627f7eb2Smrg {
4837627f7eb2Smrg if (gfc_expr_walker (&ar->start[i], has_var, (void *) (ind[j].sym)))
4838627f7eb2Smrg ind[j].n[i]++;
4839627f7eb2Smrg }
4840627f7eb2Smrg }
4841627f7eb2Smrg return 0;
4842627f7eb2Smrg }
4843627f7eb2Smrg
4844627f7eb2Smrg /* Callback function for qsort, to sort the loop indices. */
4845627f7eb2Smrg
4846627f7eb2Smrg static int
loop_comp(const void * e1,const void * e2)4847627f7eb2Smrg loop_comp (const void *e1, const void *e2)
4848627f7eb2Smrg {
4849627f7eb2Smrg const ind_type *i1 = (const ind_type *) e1;
4850627f7eb2Smrg const ind_type *i2 = (const ind_type *) e2;
4851627f7eb2Smrg int i;
4852627f7eb2Smrg
4853627f7eb2Smrg for (i=GFC_MAX_DIMENSIONS-1; i >= 0; i--)
4854627f7eb2Smrg {
4855627f7eb2Smrg if (i1->n[i] != i2->n[i])
4856627f7eb2Smrg return i1->n[i] - i2->n[i];
4857627f7eb2Smrg }
4858627f7eb2Smrg /* All other things being equal, let's not change the ordering. */
4859627f7eb2Smrg return i2->num - i1->num;
4860627f7eb2Smrg }
4861627f7eb2Smrg
4862627f7eb2Smrg /* Main function to do the index interchange. */
4863627f7eb2Smrg
4864627f7eb2Smrg static int
index_interchange(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)4865627f7eb2Smrg index_interchange (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
4866627f7eb2Smrg void *data ATTRIBUTE_UNUSED)
4867627f7eb2Smrg {
4868627f7eb2Smrg gfc_code *co;
4869627f7eb2Smrg co = *c;
4870627f7eb2Smrg int n_iter;
4871627f7eb2Smrg gfc_forall_iterator *fa;
4872627f7eb2Smrg ind_type *ind;
4873627f7eb2Smrg int i, j;
4874627f7eb2Smrg
4875627f7eb2Smrg if (co->op != EXEC_FORALL && co->op != EXEC_DO_CONCURRENT)
4876627f7eb2Smrg return 0;
4877627f7eb2Smrg
4878627f7eb2Smrg n_iter = 0;
4879627f7eb2Smrg for (fa = co->ext.forall_iterator; fa; fa = fa->next)
4880627f7eb2Smrg n_iter ++;
4881627f7eb2Smrg
4882627f7eb2Smrg /* Nothing to reorder. */
4883627f7eb2Smrg if (n_iter < 2)
4884627f7eb2Smrg return 0;
4885627f7eb2Smrg
4886627f7eb2Smrg ind = XALLOCAVEC (ind_type, n_iter + 1);
4887627f7eb2Smrg
4888627f7eb2Smrg i = 0;
4889627f7eb2Smrg for (fa = co->ext.forall_iterator; fa; fa = fa->next)
4890627f7eb2Smrg {
4891627f7eb2Smrg ind[i].sym = fa->var->symtree->n.sym;
4892627f7eb2Smrg ind[i].fa = fa;
4893627f7eb2Smrg for (j=0; j<GFC_MAX_DIMENSIONS; j++)
4894627f7eb2Smrg ind[i].n[j] = 0;
4895627f7eb2Smrg ind[i].num = i;
4896627f7eb2Smrg i++;
4897627f7eb2Smrg }
4898627f7eb2Smrg ind[n_iter].sym = NULL;
4899627f7eb2Smrg ind[n_iter].fa = NULL;
4900627f7eb2Smrg
4901627f7eb2Smrg gfc_code_walker (c, gfc_dummy_code_callback, index_cost, (void *) ind);
4902627f7eb2Smrg qsort ((void *) ind, n_iter, sizeof (ind_type), loop_comp);
4903627f7eb2Smrg
4904627f7eb2Smrg /* Do the actual index interchange. */
4905627f7eb2Smrg co->ext.forall_iterator = fa = ind[0].fa;
4906627f7eb2Smrg for (i=1; i<n_iter; i++)
4907627f7eb2Smrg {
4908627f7eb2Smrg fa->next = ind[i].fa;
4909627f7eb2Smrg fa = fa->next;
4910627f7eb2Smrg }
4911627f7eb2Smrg fa->next = NULL;
4912627f7eb2Smrg
4913627f7eb2Smrg if (flag_warn_frontend_loop_interchange)
4914627f7eb2Smrg {
4915627f7eb2Smrg for (i=1; i<n_iter; i++)
4916627f7eb2Smrg {
4917627f7eb2Smrg if (ind[i-1].num > ind[i].num)
4918627f7eb2Smrg {
4919627f7eb2Smrg gfc_warning (OPT_Wfrontend_loop_interchange,
4920627f7eb2Smrg "Interchanging loops at %L", &co->loc);
4921627f7eb2Smrg break;
4922627f7eb2Smrg }
4923627f7eb2Smrg }
4924627f7eb2Smrg }
4925627f7eb2Smrg
4926627f7eb2Smrg return 0;
4927627f7eb2Smrg }
4928627f7eb2Smrg
4929627f7eb2Smrg #define WALK_SUBEXPR(NODE) \
4930627f7eb2Smrg do \
4931627f7eb2Smrg { \
4932627f7eb2Smrg result = gfc_expr_walker (&(NODE), exprfn, data); \
4933627f7eb2Smrg if (result) \
4934627f7eb2Smrg return result; \
4935627f7eb2Smrg } \
4936627f7eb2Smrg while (0)
4937627f7eb2Smrg #define WALK_SUBEXPR_TAIL(NODE) e = &(NODE); continue
4938627f7eb2Smrg
4939627f7eb2Smrg /* Walk expression *E, calling EXPRFN on each expression in it. */
4940627f7eb2Smrg
4941627f7eb2Smrg int
gfc_expr_walker(gfc_expr ** e,walk_expr_fn_t exprfn,void * data)4942627f7eb2Smrg gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data)
4943627f7eb2Smrg {
4944627f7eb2Smrg while (*e)
4945627f7eb2Smrg {
4946627f7eb2Smrg int walk_subtrees = 1;
4947627f7eb2Smrg gfc_actual_arglist *a;
4948627f7eb2Smrg gfc_ref *r;
4949627f7eb2Smrg gfc_constructor *c;
4950627f7eb2Smrg
4951627f7eb2Smrg int result = exprfn (e, &walk_subtrees, data);
4952627f7eb2Smrg if (result)
4953627f7eb2Smrg return result;
4954627f7eb2Smrg if (walk_subtrees)
4955627f7eb2Smrg switch ((*e)->expr_type)
4956627f7eb2Smrg {
4957627f7eb2Smrg case EXPR_OP:
4958627f7eb2Smrg WALK_SUBEXPR ((*e)->value.op.op1);
4959627f7eb2Smrg WALK_SUBEXPR_TAIL ((*e)->value.op.op2);
4960627f7eb2Smrg break;
4961627f7eb2Smrg case EXPR_FUNCTION:
4962627f7eb2Smrg for (a = (*e)->value.function.actual; a; a = a->next)
4963627f7eb2Smrg WALK_SUBEXPR (a->expr);
4964627f7eb2Smrg break;
4965627f7eb2Smrg case EXPR_COMPCALL:
4966627f7eb2Smrg case EXPR_PPC:
4967627f7eb2Smrg WALK_SUBEXPR ((*e)->value.compcall.base_object);
4968627f7eb2Smrg for (a = (*e)->value.compcall.actual; a; a = a->next)
4969627f7eb2Smrg WALK_SUBEXPR (a->expr);
4970627f7eb2Smrg break;
4971627f7eb2Smrg
4972627f7eb2Smrg case EXPR_STRUCTURE:
4973627f7eb2Smrg case EXPR_ARRAY:
4974627f7eb2Smrg for (c = gfc_constructor_first ((*e)->value.constructor); c;
4975627f7eb2Smrg c = gfc_constructor_next (c))
4976627f7eb2Smrg {
4977627f7eb2Smrg if (c->iterator == NULL)
4978627f7eb2Smrg WALK_SUBEXPR (c->expr);
4979627f7eb2Smrg else
4980627f7eb2Smrg {
4981627f7eb2Smrg iterator_level ++;
4982627f7eb2Smrg WALK_SUBEXPR (c->expr);
4983627f7eb2Smrg iterator_level --;
4984627f7eb2Smrg WALK_SUBEXPR (c->iterator->var);
4985627f7eb2Smrg WALK_SUBEXPR (c->iterator->start);
4986627f7eb2Smrg WALK_SUBEXPR (c->iterator->end);
4987627f7eb2Smrg WALK_SUBEXPR (c->iterator->step);
4988627f7eb2Smrg }
4989627f7eb2Smrg }
4990627f7eb2Smrg
4991627f7eb2Smrg if ((*e)->expr_type != EXPR_ARRAY)
4992627f7eb2Smrg break;
4993627f7eb2Smrg
4994627f7eb2Smrg /* Fall through to the variable case in order to walk the
4995627f7eb2Smrg reference. */
4996627f7eb2Smrg gcc_fallthrough ();
4997627f7eb2Smrg
4998627f7eb2Smrg case EXPR_SUBSTRING:
4999627f7eb2Smrg case EXPR_VARIABLE:
5000627f7eb2Smrg for (r = (*e)->ref; r; r = r->next)
5001627f7eb2Smrg {
5002627f7eb2Smrg gfc_array_ref *ar;
5003627f7eb2Smrg int i;
5004627f7eb2Smrg
5005627f7eb2Smrg switch (r->type)
5006627f7eb2Smrg {
5007627f7eb2Smrg case REF_ARRAY:
5008627f7eb2Smrg ar = &r->u.ar;
5009627f7eb2Smrg if (ar->type == AR_SECTION || ar->type == AR_ELEMENT)
5010627f7eb2Smrg {
5011627f7eb2Smrg for (i=0; i< ar->dimen; i++)
5012627f7eb2Smrg {
5013627f7eb2Smrg WALK_SUBEXPR (ar->start[i]);
5014627f7eb2Smrg WALK_SUBEXPR (ar->end[i]);
5015627f7eb2Smrg WALK_SUBEXPR (ar->stride[i]);
5016627f7eb2Smrg }
5017627f7eb2Smrg }
5018627f7eb2Smrg
5019627f7eb2Smrg break;
5020627f7eb2Smrg
5021627f7eb2Smrg case REF_SUBSTRING:
5022627f7eb2Smrg WALK_SUBEXPR (r->u.ss.start);
5023627f7eb2Smrg WALK_SUBEXPR (r->u.ss.end);
5024627f7eb2Smrg break;
5025627f7eb2Smrg
5026627f7eb2Smrg case REF_COMPONENT:
5027627f7eb2Smrg case REF_INQUIRY:
5028627f7eb2Smrg break;
5029627f7eb2Smrg }
5030627f7eb2Smrg }
5031627f7eb2Smrg
5032627f7eb2Smrg default:
5033627f7eb2Smrg break;
5034627f7eb2Smrg }
5035627f7eb2Smrg return 0;
5036627f7eb2Smrg }
5037627f7eb2Smrg return 0;
5038627f7eb2Smrg }
5039627f7eb2Smrg
5040627f7eb2Smrg #define WALK_SUBCODE(NODE) \
5041627f7eb2Smrg do \
5042627f7eb2Smrg { \
5043627f7eb2Smrg result = gfc_code_walker (&(NODE), codefn, exprfn, data); \
5044627f7eb2Smrg if (result) \
5045627f7eb2Smrg return result; \
5046627f7eb2Smrg } \
5047627f7eb2Smrg while (0)
5048627f7eb2Smrg
5049627f7eb2Smrg /* Walk code *C, calling CODEFN on each gfc_code node in it and calling EXPRFN
5050627f7eb2Smrg on each expression in it. If any of the hooks returns non-zero, that
5051627f7eb2Smrg value is immediately returned. If the hook sets *WALK_SUBTREES to 0,
5052627f7eb2Smrg no subcodes or subexpressions are traversed. */
5053627f7eb2Smrg
5054627f7eb2Smrg int
gfc_code_walker(gfc_code ** c,walk_code_fn_t codefn,walk_expr_fn_t exprfn,void * data)5055627f7eb2Smrg gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
5056627f7eb2Smrg void *data)
5057627f7eb2Smrg {
5058627f7eb2Smrg for (; *c; c = &(*c)->next)
5059627f7eb2Smrg {
5060627f7eb2Smrg int walk_subtrees = 1;
5061627f7eb2Smrg int result = codefn (c, &walk_subtrees, data);
5062627f7eb2Smrg if (result)
5063627f7eb2Smrg return result;
5064627f7eb2Smrg
5065627f7eb2Smrg if (walk_subtrees)
5066627f7eb2Smrg {
5067627f7eb2Smrg gfc_code *b;
5068627f7eb2Smrg gfc_actual_arglist *a;
5069627f7eb2Smrg gfc_code *co;
5070627f7eb2Smrg gfc_association_list *alist;
5071627f7eb2Smrg bool saved_in_omp_workshare;
5072627f7eb2Smrg bool saved_in_omp_atomic;
5073627f7eb2Smrg bool saved_in_where;
5074627f7eb2Smrg
5075627f7eb2Smrg /* There might be statement insertions before the current code,
5076627f7eb2Smrg which must not affect the expression walker. */
5077627f7eb2Smrg
5078627f7eb2Smrg co = *c;
5079627f7eb2Smrg saved_in_omp_workshare = in_omp_workshare;
5080627f7eb2Smrg saved_in_omp_atomic = in_omp_atomic;
5081627f7eb2Smrg saved_in_where = in_where;
5082627f7eb2Smrg
5083627f7eb2Smrg switch (co->op)
5084627f7eb2Smrg {
5085627f7eb2Smrg
5086627f7eb2Smrg case EXEC_BLOCK:
5087627f7eb2Smrg WALK_SUBCODE (co->ext.block.ns->code);
5088627f7eb2Smrg if (co->ext.block.assoc)
5089627f7eb2Smrg {
5090627f7eb2Smrg bool saved_in_assoc_list = in_assoc_list;
5091627f7eb2Smrg
5092627f7eb2Smrg in_assoc_list = true;
5093627f7eb2Smrg for (alist = co->ext.block.assoc; alist; alist = alist->next)
5094627f7eb2Smrg WALK_SUBEXPR (alist->target);
5095627f7eb2Smrg
5096627f7eb2Smrg in_assoc_list = saved_in_assoc_list;
5097627f7eb2Smrg }
5098627f7eb2Smrg
5099627f7eb2Smrg break;
5100627f7eb2Smrg
5101627f7eb2Smrg case EXEC_DO:
5102627f7eb2Smrg doloop_level ++;
5103627f7eb2Smrg WALK_SUBEXPR (co->ext.iterator->var);
5104627f7eb2Smrg WALK_SUBEXPR (co->ext.iterator->start);
5105627f7eb2Smrg WALK_SUBEXPR (co->ext.iterator->end);
5106627f7eb2Smrg WALK_SUBEXPR (co->ext.iterator->step);
5107627f7eb2Smrg break;
5108627f7eb2Smrg
5109627f7eb2Smrg case EXEC_IF:
5110627f7eb2Smrg if_level ++;
5111627f7eb2Smrg break;
5112627f7eb2Smrg
5113627f7eb2Smrg case EXEC_WHERE:
5114627f7eb2Smrg in_where = true;
5115627f7eb2Smrg break;
5116627f7eb2Smrg
5117627f7eb2Smrg case EXEC_CALL:
5118627f7eb2Smrg case EXEC_ASSIGN_CALL:
5119627f7eb2Smrg for (a = co->ext.actual; a; a = a->next)
5120627f7eb2Smrg WALK_SUBEXPR (a->expr);
5121627f7eb2Smrg break;
5122627f7eb2Smrg
5123627f7eb2Smrg case EXEC_CALL_PPC:
5124627f7eb2Smrg WALK_SUBEXPR (co->expr1);
5125627f7eb2Smrg for (a = co->ext.actual; a; a = a->next)
5126627f7eb2Smrg WALK_SUBEXPR (a->expr);
5127627f7eb2Smrg break;
5128627f7eb2Smrg
5129627f7eb2Smrg case EXEC_SELECT:
5130627f7eb2Smrg WALK_SUBEXPR (co->expr1);
5131627f7eb2Smrg select_level ++;
5132627f7eb2Smrg for (b = co->block; b; b = b->block)
5133627f7eb2Smrg {
5134627f7eb2Smrg gfc_case *cp;
5135627f7eb2Smrg for (cp = b->ext.block.case_list; cp; cp = cp->next)
5136627f7eb2Smrg {
5137627f7eb2Smrg WALK_SUBEXPR (cp->low);
5138627f7eb2Smrg WALK_SUBEXPR (cp->high);
5139627f7eb2Smrg }
5140627f7eb2Smrg WALK_SUBCODE (b->next);
5141627f7eb2Smrg }
5142627f7eb2Smrg continue;
5143627f7eb2Smrg
5144627f7eb2Smrg case EXEC_ALLOCATE:
5145627f7eb2Smrg case EXEC_DEALLOCATE:
5146627f7eb2Smrg {
5147627f7eb2Smrg gfc_alloc *a;
5148627f7eb2Smrg for (a = co->ext.alloc.list; a; a = a->next)
5149627f7eb2Smrg WALK_SUBEXPR (a->expr);
5150627f7eb2Smrg break;
5151627f7eb2Smrg }
5152627f7eb2Smrg
5153627f7eb2Smrg case EXEC_FORALL:
5154627f7eb2Smrg case EXEC_DO_CONCURRENT:
5155627f7eb2Smrg {
5156627f7eb2Smrg gfc_forall_iterator *fa;
5157627f7eb2Smrg for (fa = co->ext.forall_iterator; fa; fa = fa->next)
5158627f7eb2Smrg {
5159627f7eb2Smrg WALK_SUBEXPR (fa->var);
5160627f7eb2Smrg WALK_SUBEXPR (fa->start);
5161627f7eb2Smrg WALK_SUBEXPR (fa->end);
5162627f7eb2Smrg WALK_SUBEXPR (fa->stride);
5163627f7eb2Smrg }
5164627f7eb2Smrg if (co->op == EXEC_FORALL)
5165627f7eb2Smrg forall_level ++;
5166627f7eb2Smrg break;
5167627f7eb2Smrg }
5168627f7eb2Smrg
5169627f7eb2Smrg case EXEC_OPEN:
5170627f7eb2Smrg WALK_SUBEXPR (co->ext.open->unit);
5171627f7eb2Smrg WALK_SUBEXPR (co->ext.open->file);
5172627f7eb2Smrg WALK_SUBEXPR (co->ext.open->status);
5173627f7eb2Smrg WALK_SUBEXPR (co->ext.open->access);
5174627f7eb2Smrg WALK_SUBEXPR (co->ext.open->form);
5175627f7eb2Smrg WALK_SUBEXPR (co->ext.open->recl);
5176627f7eb2Smrg WALK_SUBEXPR (co->ext.open->blank);
5177627f7eb2Smrg WALK_SUBEXPR (co->ext.open->position);
5178627f7eb2Smrg WALK_SUBEXPR (co->ext.open->action);
5179627f7eb2Smrg WALK_SUBEXPR (co->ext.open->delim);
5180627f7eb2Smrg WALK_SUBEXPR (co->ext.open->pad);
5181627f7eb2Smrg WALK_SUBEXPR (co->ext.open->iostat);
5182627f7eb2Smrg WALK_SUBEXPR (co->ext.open->iomsg);
5183627f7eb2Smrg WALK_SUBEXPR (co->ext.open->convert);
5184627f7eb2Smrg WALK_SUBEXPR (co->ext.open->decimal);
5185627f7eb2Smrg WALK_SUBEXPR (co->ext.open->encoding);
5186627f7eb2Smrg WALK_SUBEXPR (co->ext.open->round);
5187627f7eb2Smrg WALK_SUBEXPR (co->ext.open->sign);
5188627f7eb2Smrg WALK_SUBEXPR (co->ext.open->asynchronous);
5189627f7eb2Smrg WALK_SUBEXPR (co->ext.open->id);
5190627f7eb2Smrg WALK_SUBEXPR (co->ext.open->newunit);
5191627f7eb2Smrg WALK_SUBEXPR (co->ext.open->share);
5192627f7eb2Smrg WALK_SUBEXPR (co->ext.open->cc);
5193627f7eb2Smrg break;
5194627f7eb2Smrg
5195627f7eb2Smrg case EXEC_CLOSE:
5196627f7eb2Smrg WALK_SUBEXPR (co->ext.close->unit);
5197627f7eb2Smrg WALK_SUBEXPR (co->ext.close->status);
5198627f7eb2Smrg WALK_SUBEXPR (co->ext.close->iostat);
5199627f7eb2Smrg WALK_SUBEXPR (co->ext.close->iomsg);
5200627f7eb2Smrg break;
5201627f7eb2Smrg
5202627f7eb2Smrg case EXEC_BACKSPACE:
5203627f7eb2Smrg case EXEC_ENDFILE:
5204627f7eb2Smrg case EXEC_REWIND:
5205627f7eb2Smrg case EXEC_FLUSH:
5206627f7eb2Smrg WALK_SUBEXPR (co->ext.filepos->unit);
5207627f7eb2Smrg WALK_SUBEXPR (co->ext.filepos->iostat);
5208627f7eb2Smrg WALK_SUBEXPR (co->ext.filepos->iomsg);
5209627f7eb2Smrg break;
5210627f7eb2Smrg
5211627f7eb2Smrg case EXEC_INQUIRE:
5212627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->unit);
5213627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->file);
5214627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->iomsg);
5215627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->iostat);
5216627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->exist);
5217627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->opened);
5218627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->number);
5219627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->named);
5220627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->name);
5221627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->access);
5222627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->sequential);
5223627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->direct);
5224627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->form);
5225627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->formatted);
5226627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->unformatted);
5227627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->recl);
5228627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->nextrec);
5229627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->blank);
5230627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->position);
5231627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->action);
5232627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->read);
5233627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->write);
5234627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->readwrite);
5235627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->delim);
5236627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->encoding);
5237627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->pad);
5238627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->iolength);
5239627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->convert);
5240627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->strm_pos);
5241627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->asynchronous);
5242627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->decimal);
5243627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->pending);
5244627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->id);
5245627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->sign);
5246627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->size);
5247627f7eb2Smrg WALK_SUBEXPR (co->ext.inquire->round);
5248627f7eb2Smrg break;
5249627f7eb2Smrg
5250627f7eb2Smrg case EXEC_WAIT:
5251627f7eb2Smrg WALK_SUBEXPR (co->ext.wait->unit);
5252627f7eb2Smrg WALK_SUBEXPR (co->ext.wait->iostat);
5253627f7eb2Smrg WALK_SUBEXPR (co->ext.wait->iomsg);
5254627f7eb2Smrg WALK_SUBEXPR (co->ext.wait->id);
5255627f7eb2Smrg break;
5256627f7eb2Smrg
5257627f7eb2Smrg case EXEC_READ:
5258627f7eb2Smrg case EXEC_WRITE:
5259627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->io_unit);
5260627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->format_expr);
5261627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->rec);
5262627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->advance);
5263627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->iostat);
5264627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->size);
5265627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->iomsg);
5266627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->id);
5267627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->pos);
5268627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->asynchronous);
5269627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->blank);
5270627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->decimal);
5271627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->delim);
5272627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->pad);
5273627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->round);
5274627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->sign);
5275627f7eb2Smrg WALK_SUBEXPR (co->ext.dt->extra_comma);
5276627f7eb2Smrg break;
5277627f7eb2Smrg
5278627f7eb2Smrg case EXEC_OACC_ATOMIC:
5279627f7eb2Smrg case EXEC_OMP_ATOMIC:
5280627f7eb2Smrg in_omp_atomic = true;
5281627f7eb2Smrg break;
5282627f7eb2Smrg
5283627f7eb2Smrg case EXEC_OMP_PARALLEL:
5284627f7eb2Smrg case EXEC_OMP_PARALLEL_DO:
5285627f7eb2Smrg case EXEC_OMP_PARALLEL_DO_SIMD:
5286627f7eb2Smrg case EXEC_OMP_PARALLEL_SECTIONS:
5287627f7eb2Smrg
5288627f7eb2Smrg in_omp_workshare = false;
5289627f7eb2Smrg
5290627f7eb2Smrg /* This goto serves as a shortcut to avoid code
5291627f7eb2Smrg duplication or a larger if or switch statement. */
5292627f7eb2Smrg goto check_omp_clauses;
5293627f7eb2Smrg
5294627f7eb2Smrg case EXEC_OMP_WORKSHARE:
5295627f7eb2Smrg case EXEC_OMP_PARALLEL_WORKSHARE:
5296627f7eb2Smrg
5297627f7eb2Smrg in_omp_workshare = true;
5298627f7eb2Smrg
5299627f7eb2Smrg /* Fall through */
5300627f7eb2Smrg
5301627f7eb2Smrg case EXEC_OMP_CRITICAL:
5302627f7eb2Smrg case EXEC_OMP_DISTRIBUTE:
5303627f7eb2Smrg case EXEC_OMP_DISTRIBUTE_PARALLEL_DO:
5304627f7eb2Smrg case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD:
5305627f7eb2Smrg case EXEC_OMP_DISTRIBUTE_SIMD:
5306627f7eb2Smrg case EXEC_OMP_DO:
5307627f7eb2Smrg case EXEC_OMP_DO_SIMD:
5308627f7eb2Smrg case EXEC_OMP_ORDERED:
5309627f7eb2Smrg case EXEC_OMP_SECTIONS:
5310627f7eb2Smrg case EXEC_OMP_SINGLE:
5311627f7eb2Smrg case EXEC_OMP_END_SINGLE:
5312627f7eb2Smrg case EXEC_OMP_SIMD:
5313627f7eb2Smrg case EXEC_OMP_TASKLOOP:
5314627f7eb2Smrg case EXEC_OMP_TASKLOOP_SIMD:
5315627f7eb2Smrg case EXEC_OMP_TARGET:
5316627f7eb2Smrg case EXEC_OMP_TARGET_DATA:
5317627f7eb2Smrg case EXEC_OMP_TARGET_ENTER_DATA:
5318627f7eb2Smrg case EXEC_OMP_TARGET_EXIT_DATA:
5319627f7eb2Smrg case EXEC_OMP_TARGET_PARALLEL:
5320627f7eb2Smrg case EXEC_OMP_TARGET_PARALLEL_DO:
5321627f7eb2Smrg case EXEC_OMP_TARGET_PARALLEL_DO_SIMD:
5322627f7eb2Smrg case EXEC_OMP_TARGET_SIMD:
5323627f7eb2Smrg case EXEC_OMP_TARGET_TEAMS:
5324627f7eb2Smrg case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE:
5325627f7eb2Smrg case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO:
5326627f7eb2Smrg case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
5327627f7eb2Smrg case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
5328627f7eb2Smrg case EXEC_OMP_TARGET_UPDATE:
5329627f7eb2Smrg case EXEC_OMP_TASK:
5330627f7eb2Smrg case EXEC_OMP_TEAMS:
5331627f7eb2Smrg case EXEC_OMP_TEAMS_DISTRIBUTE:
5332627f7eb2Smrg case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO:
5333627f7eb2Smrg case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
5334627f7eb2Smrg case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD:
5335627f7eb2Smrg
5336627f7eb2Smrg /* Come to this label only from the
5337627f7eb2Smrg EXEC_OMP_PARALLEL_* cases above. */
5338627f7eb2Smrg
5339627f7eb2Smrg check_omp_clauses:
5340627f7eb2Smrg
5341627f7eb2Smrg if (co->ext.omp_clauses)
5342627f7eb2Smrg {
5343627f7eb2Smrg gfc_omp_namelist *n;
5344627f7eb2Smrg static int list_types[]
5345627f7eb2Smrg = { OMP_LIST_ALIGNED, OMP_LIST_LINEAR, OMP_LIST_DEPEND,
5346627f7eb2Smrg OMP_LIST_MAP, OMP_LIST_TO, OMP_LIST_FROM };
5347627f7eb2Smrg size_t idx;
5348627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->if_expr);
5349627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->final_expr);
5350627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->num_threads);
5351627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->chunk_size);
5352627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->safelen_expr);
5353627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->simdlen_expr);
5354627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->num_teams);
5355627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->device);
5356627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->thread_limit);
5357627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->dist_chunk_size);
5358627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->grainsize);
5359627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->hint);
5360627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->num_tasks);
5361627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->priority);
5362627f7eb2Smrg for (idx = 0; idx < OMP_IF_LAST; idx++)
5363627f7eb2Smrg WALK_SUBEXPR (co->ext.omp_clauses->if_exprs[idx]);
5364627f7eb2Smrg for (idx = 0;
5365627f7eb2Smrg idx < sizeof (list_types) / sizeof (list_types[0]);
5366627f7eb2Smrg idx++)
5367627f7eb2Smrg for (n = co->ext.omp_clauses->lists[list_types[idx]];
5368627f7eb2Smrg n; n = n->next)
5369627f7eb2Smrg WALK_SUBEXPR (n->expr);
5370627f7eb2Smrg }
5371627f7eb2Smrg break;
5372627f7eb2Smrg default:
5373627f7eb2Smrg break;
5374627f7eb2Smrg }
5375627f7eb2Smrg
5376627f7eb2Smrg WALK_SUBEXPR (co->expr1);
5377627f7eb2Smrg WALK_SUBEXPR (co->expr2);
5378627f7eb2Smrg WALK_SUBEXPR (co->expr3);
5379627f7eb2Smrg WALK_SUBEXPR (co->expr4);
5380627f7eb2Smrg for (b = co->block; b; b = b->block)
5381627f7eb2Smrg {
5382627f7eb2Smrg WALK_SUBEXPR (b->expr1);
5383627f7eb2Smrg WALK_SUBEXPR (b->expr2);
5384627f7eb2Smrg WALK_SUBCODE (b->next);
5385627f7eb2Smrg }
5386627f7eb2Smrg
5387627f7eb2Smrg if (co->op == EXEC_FORALL)
5388627f7eb2Smrg forall_level --;
5389627f7eb2Smrg
5390627f7eb2Smrg if (co->op == EXEC_DO)
5391627f7eb2Smrg doloop_level --;
5392627f7eb2Smrg
5393627f7eb2Smrg if (co->op == EXEC_IF)
5394627f7eb2Smrg if_level --;
5395627f7eb2Smrg
5396627f7eb2Smrg if (co->op == EXEC_SELECT)
5397627f7eb2Smrg select_level --;
5398627f7eb2Smrg
5399627f7eb2Smrg in_omp_workshare = saved_in_omp_workshare;
5400627f7eb2Smrg in_omp_atomic = saved_in_omp_atomic;
5401627f7eb2Smrg in_where = saved_in_where;
5402627f7eb2Smrg }
5403627f7eb2Smrg }
5404627f7eb2Smrg return 0;
5405627f7eb2Smrg }
5406*4c3eb207Smrg
5407*4c3eb207Smrg /* As a post-resolution step, check that all global symbols which are
5408*4c3eb207Smrg not declared in the source file match in their call signatures.
5409*4c3eb207Smrg We do this by looping over the code (and expressions). The first call
5410*4c3eb207Smrg we happen to find is assumed to be canonical. */
5411*4c3eb207Smrg
5412*4c3eb207Smrg
5413*4c3eb207Smrg /* Common tests for argument checking for both functions and subroutines. */
5414*4c3eb207Smrg
5415*4c3eb207Smrg static int
check_externals_procedure(gfc_symbol * sym,locus * loc,gfc_actual_arglist * actual)5416*4c3eb207Smrg check_externals_procedure (gfc_symbol *sym, locus *loc,
5417*4c3eb207Smrg gfc_actual_arglist *actual)
5418*4c3eb207Smrg {
5419*4c3eb207Smrg gfc_gsymbol *gsym;
5420*4c3eb207Smrg gfc_symbol *def_sym = NULL;
5421*4c3eb207Smrg
5422*4c3eb207Smrg if (sym == NULL || sym->attr.is_bind_c)
5423*4c3eb207Smrg return 0;
5424*4c3eb207Smrg
5425*4c3eb207Smrg if (sym->attr.proc != PROC_EXTERNAL && sym->attr.proc != PROC_UNKNOWN)
5426*4c3eb207Smrg return 0;
5427*4c3eb207Smrg
5428*4c3eb207Smrg if (sym->attr.if_source == IFSRC_IFBODY || sym->attr.if_source == IFSRC_DECL)
5429*4c3eb207Smrg return 0;
5430*4c3eb207Smrg
5431*4c3eb207Smrg gsym = gfc_find_gsymbol (gfc_gsym_root, sym->name);
5432*4c3eb207Smrg if (gsym == NULL)
5433*4c3eb207Smrg return 0;
5434*4c3eb207Smrg
5435*4c3eb207Smrg if (gsym->ns)
5436*4c3eb207Smrg gfc_find_symbol (sym->name, gsym->ns, 0, &def_sym);
5437*4c3eb207Smrg
5438*4c3eb207Smrg if (def_sym)
5439*4c3eb207Smrg {
5440*4c3eb207Smrg gfc_compare_actual_formal (&actual, def_sym->formal, 0, 0, 0, loc);
5441*4c3eb207Smrg return 0;
5442*4c3eb207Smrg }
5443*4c3eb207Smrg
5444*4c3eb207Smrg /* First time we have seen this procedure called. Let's create an
5445*4c3eb207Smrg "interface" from the call and put it into a new namespace. */
5446*4c3eb207Smrg gfc_namespace *save_ns;
5447*4c3eb207Smrg gfc_symbol *new_sym;
5448*4c3eb207Smrg
5449*4c3eb207Smrg gsym->where = *loc;
5450*4c3eb207Smrg save_ns = gfc_current_ns;
5451*4c3eb207Smrg gsym->ns = gfc_get_namespace (gfc_current_ns, 0);
5452*4c3eb207Smrg gsym->ns->proc_name = sym;
5453*4c3eb207Smrg
5454*4c3eb207Smrg gfc_get_symbol (sym->name, gsym->ns, &new_sym);
5455*4c3eb207Smrg gcc_assert (new_sym);
5456*4c3eb207Smrg new_sym->attr = sym->attr;
5457*4c3eb207Smrg new_sym->attr.if_source = IFSRC_DECL;
5458*4c3eb207Smrg gfc_current_ns = gsym->ns;
5459*4c3eb207Smrg
5460*4c3eb207Smrg gfc_get_formal_from_actual_arglist (new_sym, actual);
5461*4c3eb207Smrg gfc_current_ns = save_ns;
5462*4c3eb207Smrg
5463*4c3eb207Smrg return 0;
5464*4c3eb207Smrg
5465*4c3eb207Smrg }
5466*4c3eb207Smrg
5467*4c3eb207Smrg /* Callback for calls of external routines. */
5468*4c3eb207Smrg
5469*4c3eb207Smrg static int
check_externals_code(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)5470*4c3eb207Smrg check_externals_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
5471*4c3eb207Smrg void *data ATTRIBUTE_UNUSED)
5472*4c3eb207Smrg {
5473*4c3eb207Smrg gfc_code *co = *c;
5474*4c3eb207Smrg gfc_symbol *sym;
5475*4c3eb207Smrg locus *loc;
5476*4c3eb207Smrg gfc_actual_arglist *actual;
5477*4c3eb207Smrg
5478*4c3eb207Smrg if (co->op != EXEC_CALL)
5479*4c3eb207Smrg return 0;
5480*4c3eb207Smrg
5481*4c3eb207Smrg sym = co->resolved_sym;
5482*4c3eb207Smrg loc = &co->loc;
5483*4c3eb207Smrg actual = co->ext.actual;
5484*4c3eb207Smrg
5485*4c3eb207Smrg return check_externals_procedure (sym, loc, actual);
5486*4c3eb207Smrg
5487*4c3eb207Smrg }
5488*4c3eb207Smrg
5489*4c3eb207Smrg /* Callback for external functions. */
5490*4c3eb207Smrg
5491*4c3eb207Smrg static int
check_externals_expr(gfc_expr ** ep,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)5492*4c3eb207Smrg check_externals_expr (gfc_expr **ep, int *walk_subtrees ATTRIBUTE_UNUSED,
5493*4c3eb207Smrg void *data ATTRIBUTE_UNUSED)
5494*4c3eb207Smrg {
5495*4c3eb207Smrg gfc_expr *e = *ep;
5496*4c3eb207Smrg gfc_symbol *sym;
5497*4c3eb207Smrg locus *loc;
5498*4c3eb207Smrg gfc_actual_arglist *actual;
5499*4c3eb207Smrg
5500*4c3eb207Smrg if (e->expr_type != EXPR_FUNCTION)
5501*4c3eb207Smrg return 0;
5502*4c3eb207Smrg
5503*4c3eb207Smrg sym = e->value.function.esym;
5504*4c3eb207Smrg if (sym == NULL)
5505*4c3eb207Smrg return 0;
5506*4c3eb207Smrg
5507*4c3eb207Smrg loc = &e->where;
5508*4c3eb207Smrg actual = e->value.function.actual;
5509*4c3eb207Smrg
5510*4c3eb207Smrg return check_externals_procedure (sym, loc, actual);
5511*4c3eb207Smrg }
5512*4c3eb207Smrg
5513*4c3eb207Smrg /* Called routine. */
5514*4c3eb207Smrg
5515*4c3eb207Smrg void
gfc_check_externals(gfc_namespace * ns)5516*4c3eb207Smrg gfc_check_externals (gfc_namespace *ns)
5517*4c3eb207Smrg {
5518*4c3eb207Smrg
5519*4c3eb207Smrg gfc_clear_error ();
5520*4c3eb207Smrg
5521*4c3eb207Smrg /* Turn errors into warnings if the user indicated this. */
5522*4c3eb207Smrg
5523*4c3eb207Smrg if (!pedantic && flag_allow_argument_mismatch)
5524*4c3eb207Smrg gfc_errors_to_warnings (true);
5525*4c3eb207Smrg
5526*4c3eb207Smrg gfc_code_walker (&ns->code, check_externals_code, check_externals_expr, NULL);
5527*4c3eb207Smrg
5528*4c3eb207Smrg for (ns = ns->contained; ns; ns = ns->sibling)
5529*4c3eb207Smrg {
5530*4c3eb207Smrg if (ns->code == NULL || ns->code->op != EXEC_BLOCK)
5531*4c3eb207Smrg gfc_check_externals (ns);
5532*4c3eb207Smrg }
5533*4c3eb207Smrg
5534*4c3eb207Smrg gfc_errors_to_warnings (false);
5535*4c3eb207Smrg }
5536*4c3eb207Smrg
5537*4c3eb207Smrg /* Callback function. If there is a call to a subroutine which is
5538*4c3eb207Smrg neither pure nor implicit_pure, unset the implicit_pure flag for
5539*4c3eb207Smrg the caller and return -1. */
5540*4c3eb207Smrg
5541*4c3eb207Smrg static int
implicit_pure_call(gfc_code ** c,int * walk_subtrees ATTRIBUTE_UNUSED,void * sym_data)5542*4c3eb207Smrg implicit_pure_call (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
5543*4c3eb207Smrg void *sym_data)
5544*4c3eb207Smrg {
5545*4c3eb207Smrg gfc_code *co = *c;
5546*4c3eb207Smrg gfc_symbol *caller_sym;
5547*4c3eb207Smrg symbol_attribute *a;
5548*4c3eb207Smrg
5549*4c3eb207Smrg if (co->op != EXEC_CALL || co->resolved_sym == NULL)
5550*4c3eb207Smrg return 0;
5551*4c3eb207Smrg
5552*4c3eb207Smrg a = &co->resolved_sym->attr;
5553*4c3eb207Smrg if (a->intrinsic || a->pure || a->implicit_pure)
5554*4c3eb207Smrg return 0;
5555*4c3eb207Smrg
5556*4c3eb207Smrg caller_sym = (gfc_symbol *) sym_data;
5557*4c3eb207Smrg gfc_unset_implicit_pure (caller_sym);
5558*4c3eb207Smrg return 1;
5559*4c3eb207Smrg }
5560*4c3eb207Smrg
5561*4c3eb207Smrg /* Callback function. If there is a call to a function which is
5562*4c3eb207Smrg neither pure nor implicit_pure, unset the implicit_pure flag for
5563*4c3eb207Smrg the caller and return 1. */
5564*4c3eb207Smrg
5565*4c3eb207Smrg static int
implicit_pure_expr(gfc_expr ** e,int * walk ATTRIBUTE_UNUSED,void * sym_data)5566*4c3eb207Smrg implicit_pure_expr (gfc_expr **e, int *walk ATTRIBUTE_UNUSED, void *sym_data)
5567*4c3eb207Smrg {
5568*4c3eb207Smrg gfc_expr *expr = *e;
5569*4c3eb207Smrg gfc_symbol *caller_sym;
5570*4c3eb207Smrg gfc_symbol *sym;
5571*4c3eb207Smrg symbol_attribute *a;
5572*4c3eb207Smrg
5573*4c3eb207Smrg if (expr->expr_type != EXPR_FUNCTION || expr->value.function.isym)
5574*4c3eb207Smrg return 0;
5575*4c3eb207Smrg
5576*4c3eb207Smrg sym = expr->symtree->n.sym;
5577*4c3eb207Smrg a = &sym->attr;
5578*4c3eb207Smrg if (a->pure || a->implicit_pure)
5579*4c3eb207Smrg return 0;
5580*4c3eb207Smrg
5581*4c3eb207Smrg caller_sym = (gfc_symbol *) sym_data;
5582*4c3eb207Smrg gfc_unset_implicit_pure (caller_sym);
5583*4c3eb207Smrg return 1;
5584*4c3eb207Smrg }
5585*4c3eb207Smrg
5586*4c3eb207Smrg /* Go through all procedures in the namespace and unset the
5587*4c3eb207Smrg implicit_pure attribute for any procedure that calls something not
5588*4c3eb207Smrg pure or implicit pure. */
5589*4c3eb207Smrg
5590*4c3eb207Smrg bool
gfc_fix_implicit_pure(gfc_namespace * ns)5591*4c3eb207Smrg gfc_fix_implicit_pure (gfc_namespace *ns)
5592*4c3eb207Smrg {
5593*4c3eb207Smrg bool changed = false;
5594*4c3eb207Smrg gfc_symbol *proc = ns->proc_name;
5595*4c3eb207Smrg
5596*4c3eb207Smrg if (proc && proc->attr.flavor == FL_PROCEDURE && proc->attr.implicit_pure
5597*4c3eb207Smrg && ns->code
5598*4c3eb207Smrg && gfc_code_walker (&ns->code, implicit_pure_call, implicit_pure_expr,
5599*4c3eb207Smrg (void *) ns->proc_name))
5600*4c3eb207Smrg changed = true;
5601*4c3eb207Smrg
5602*4c3eb207Smrg for (ns = ns->contained; ns; ns = ns->sibling)
5603*4c3eb207Smrg {
5604*4c3eb207Smrg if (gfc_fix_implicit_pure (ns))
5605*4c3eb207Smrg changed = true;
5606*4c3eb207Smrg }
5607*4c3eb207Smrg
5608*4c3eb207Smrg return changed;
5609*4c3eb207Smrg }
5610