From patchwork Mon Oct 14 15:08:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikael Morin X-Patchwork-Id: 1997020 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=orange.fr header.i=@orange.fr header.a=rsa-sha256 header.s=t20230301 header.b=fJ9k2Ys+; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XS0xx4Y82z1xvK for ; Tue, 15 Oct 2024 02:09:25 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5C29F385AE6D for ; Mon, 14 Oct 2024 15:09:23 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtp.smtpout.orange.fr (smtp-18.smtpout.orange.fr [80.12.242.18]) by sourceware.org (Postfix) with ESMTPS id 5AF343857022; Mon, 14 Oct 2024 15:08:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5AF343857022 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=orange.fr Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=orange.fr ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5AF343857022 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=80.12.242.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1728918517; cv=none; b=xY0wkoznmxez6TktpyXstqKOj87E4w9EhJnPjhIbzyYcv8s2X8jaim3by98TZjJqDjvd84YQGdFqQKNgSluEWKTKS1eo84z6fohC0b2I4/QmJ3JvCLkcHJNFT5GdxNqMR8xndW6kFVwoUs8leqPW6CVvdB8kWRVUQE1lTtAVpqc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1728918517; c=relaxed/simple; bh=BXhJbyQJ8ELLohF+jZTLx1pDUYylkPDsF5AeNqemLwk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Kw9pxwct18c+LnAtBPXEJ/tgLXqQUsjMACY3E9fGpXBp0CdCgKoMs64ICzOc4FyIOyK8rp+a7/+6QBSDWS19HSVc5rcSagYFaeksielgruAXxrDF7JFd+IxUcbumzaTmeNylncNRCOjY8Jg9hWJfSuIiLPUfHCrTc5B30g+LjbY= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from cyrano.home ([86.215.161.51]) by smtp.orange.fr with ESMTPA id 0MgBtHlyUIPG80MgPtVhKT; Mon, 14 Oct 2024 17:08:29 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=orange.fr; s=t20230301; t=1728918509; bh=7yrk/YLDIflpYRbxaQlTf8ZTD7bskFTd0m8fP23YsN8=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=fJ9k2Ys+FZU/p1tlmtdQzD5pgw3DnIdnQOSAI0PvinHWtPgOv5wxz454qswSDvkVc BW8ask42xUDCYL/ABBcvwgluLf/wVMlBUSU6NcsTFB4Th/hSdwFTv55XlQWY4ShmFY +TIHl0V2xUtTOUrWuvDTSGQr+Ozrc/Z86XHcMevZEMZLMFTYJ498HAc+UKmoj/+4Xz 05hpUB6XnhT+fQyzU+wfmvc7Ru7nTszTS05pGrvf8RciOM4Lh8gAXDwFuAxuUon/nC PvQZZ3z4C7+FDXAoxOWXYCJ3Cbsu4EmJwNX2NkNODDrvAm/8NteveQ731/5eGmE8yJ SAxSJwHvN3+sA== X-ME-Helo: cyrano.home X-ME-Auth: bW9yaW4tbWlrYWVsQG9yYW5nZS5mcg== X-ME-Date: Mon, 14 Oct 2024 17:08:29 +0200 X-ME-IP: 86.215.161.51 From: Mikael Morin To: gcc-patches@gcc.gnu.org, fortran@gcc.gnu.org Subject: [PATCH 2/7] fortran: Inline unmasked integral MINLOC/MAXLOC with DIM [PR90608] Date: Mon, 14 Oct 2024 17:08:11 +0200 Message-ID: <20241014150816.315478-3-morin-mikael@orange.fr> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241014150816.315478-1-morin-mikael@orange.fr> References: <20241014150816.315478-1-morin-mikael@orange.fr> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org From: Mikael Morin Bootstrapped and regression-tested on x86_64-pc-linux-gnu. OK for master? -- >8 -- Enable generation of inline code for the MINLOC and MAXLOC intrinsics, if the ARRAY argument is of integral type and of rank > 1 (only the rank 1 case was previously inlined), the DIM argument is a constant value and there is no MASK argument. The restriction to integral ARRAY and absent MASK limits the scope of the change to the cases where we generate single loop inline code. This change uses the existing scalarizer suport for reductions, that is arrays used in scalarization loops, where each element uses a nested scalarization loop to calculate its value. The nested loop (and respectively the nested scalarization chain) is created while walking the MINLOC/MAXLOC expression, it's set up automatically at the time the outer loop is set up, and gfc_conv_intrinsic_minmaxloc is changed to use it as a replacement for the local loop variable (respectively ARRAY scalarization chain) used in the non-reduction case (i.e. when DIM is absent). PR fortran/90608 gcc/fortran/ChangeLog: * trans-intrinsic.cc (gfc_inline_intrinsic_function_p): Return true if DIM is constant, ARRAY is integral and MASK is absent. (walk_inline_intrinsic_minmaxloc): If DIM is present, walk ARRAY and move the dimension corresponding to DIM to a nested chain, keeping the rest of the dimensions as the returned scalarization chain. (gfc_conv_intrinsic_minmaxloc): When inside the scalarization loops, proceed with inline code generation If DIM is present. If DIM is present, skip result array creation and final initialization from individual result local variables. If DIM is present and ARRAY has rank greater than 1, use the nested loop initialized by the scalarizer instead of the local one, use 1 as scalarization dimension, and evaluate ARRAY using the inherited scalarization chain instead of creating a local one by walking the expression. gcc/testsuite/ChangeLog: * gfortran.dg/maxloc_bounds_1.f90: Also accept the error message generated by the scalarizer in case the function call is implemented through inline code. * gfortran.dg/maxloc_bounds_2.f90: Likewise. * gfortran.dg/maxloc_bounds_3.f90: Likewise. * gfortran.dg/minmaxloc_19.f90: New test. --- gcc/fortran/trans-intrinsic.cc | 229 ++++++++++++------ gcc/testsuite/gfortran.dg/maxloc_bounds_1.f90 | 4 +- gcc/testsuite/gfortran.dg/maxloc_bounds_2.f90 | 4 +- gcc/testsuite/gfortran.dg/maxloc_bounds_3.f90 | 4 +- gcc/testsuite/gfortran.dg/minmaxloc_19.f90 | 182 ++++++++++++++ 5 files changed, 344 insertions(+), 79 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/minmaxloc_19.f90 diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc index a282ae1c090..e44a245ec75 100644 --- a/gcc/fortran/trans-intrinsic.cc +++ b/gcc/fortran/trans-intrinsic.cc @@ -5472,12 +5472,14 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) tree lab1, lab2; tree b_if, b_else; tree back; - gfc_loopinfo loop; - gfc_actual_arglist *actual; - gfc_ss *arrayss; - gfc_ss *maskss; + gfc_loopinfo loop, *ploop; + gfc_actual_arglist *actual, *array_arg, *dim_arg, *mask_arg, *kind_arg; + gfc_actual_arglist *back_arg; + gfc_ss *arrayss = nullptr; + gfc_ss *maskss = nullptr; gfc_se arrayse; gfc_se maskse; + gfc_se *base_se; gfc_expr *arrayexpr; gfc_expr *maskexpr; gfc_expr *backexpr; @@ -5489,6 +5491,14 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) bool optional_mask; actual = expr->value.function.actual; + array_arg = actual; + dim_arg = array_arg->next; + mask_arg = dim_arg->next; + kind_arg = mask_arg->next; + back_arg = kind_arg->next; + + bool dim_present = dim_arg->expr != nullptr; + bool nested_loop = dim_present && expr->rank > 0; /* The last argument, BACK, is passed by value. Ensure that by setting its name to %VAL. */ @@ -5502,11 +5512,15 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) { if (se->ss->info->useflags) { - /* The inline implementation of MINLOC/MAXLOC has been generated - before, out of the scalarization loop; now we can just use the - result. */ - gfc_conv_tmp_array_ref (se); - return; + if (!dim_present || !gfc_inline_intrinsic_function_p (expr)) + { + /* The code generating and initializing the result array has been + generated already before the scalarization loop, either with a + library function call or with inline code; now we can just use + the result. */ + gfc_conv_tmp_array_ref (se); + return; + } } else if (!gfc_inline_intrinsic_function_p (expr)) { @@ -5522,8 +5536,9 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) if (arrayexpr->ts.type == BT_CHARACTER) { - gfc_actual_arglist *a; - a = actual; + gcc_assert (expr->rank == 0); + + gfc_actual_arglist *a = actual; strip_kind_from_actual (a); while (a) { @@ -5540,7 +5555,7 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) type = gfc_typenode_for_spec (&expr->ts); - if (expr->rank > 0) + if (expr->rank > 0 && !dim_present) { gfc_array_spec as; memset (&as, 0, sizeof (as)); @@ -5558,8 +5573,10 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) result_var = gfc_create_var (array, "loc_result"); } + const int reduction_dimensions = dim_present ? 1 : arrayexpr->rank; + /* Initialize the result. */ - for (int i = 0; i < arrayexpr->rank; i++) + for (int i = 0; i < reduction_dimensions; i++) { pos[i] = gfc_create_var (gfc_array_index_type, gfc_get_string ("pos%d", i)); @@ -5569,17 +5586,11 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) gfc_get_string ("idx%d", i)); } - /* Walk the arguments. */ - arrayss = gfc_walk_expr (arrayexpr); - gcc_assert (arrayss != gfc_ss_terminator); - - actual = actual->next->next; - gcc_assert (actual); - maskexpr = actual->expr; + maskexpr = mask_arg->expr; optional_mask = maskexpr && maskexpr->expr_type == EXPR_VARIABLE && maskexpr->symtree->n.sym->attr.dummy && maskexpr->symtree->n.sym->attr.optional; - backexpr = actual->next->next->expr; + backexpr = back_arg->expr; gfc_init_se (&backse, NULL); if (backexpr == nullptr) @@ -5604,13 +5615,25 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) back = gfc_evaluate_now_loc (input_location, back, &se->pre); gfc_add_block_to_block (&se->pre, &backse.post); - nonempty = NULL; - if (maskexpr && maskexpr->rank != 0) - { - maskss = gfc_walk_expr (maskexpr); - gcc_assert (maskss != gfc_ss_terminator); - } + if (nested_loop) + base_se = se; else + { + /* Walk the arguments. */ + arrayss = gfc_walk_expr (arrayexpr); + gcc_assert (arrayss != gfc_ss_terminator); + + if (maskexpr && maskexpr->rank != 0) + { + maskss = gfc_walk_expr (maskexpr); + gcc_assert (maskss != gfc_ss_terminator); + } + + base_se = nullptr; + } + + nonempty = nullptr; + if (!(maskexpr && maskexpr->rank > 0)) { mpz_t asize; if (gfc_array_size (arrayexpr, &asize)) @@ -5681,47 +5704,59 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) "second_loop_entry"); gfc_add_modify (&se->pre, second_loop_entry, logical_false_node); - /* Initialize the scalarizer. */ - gfc_init_loopinfo (&loop); + if (nested_loop) + { + ploop = enter_nested_loop (se); + ploop->temp_dim = 1; + } + else + { + /* Initialize the scalarizer. */ + gfc_init_loopinfo (&loop); - /* We add the mask first because the number of iterations is taken - from the last ss, and this breaks if an absent optional argument - is used for mask. */ + /* We add the mask first because the number of iterations is taken + from the last ss, and this breaks if an absent optional argument + is used for mask. */ - if (maskss) - gfc_add_ss_to_loop (&loop, maskss); + if (maskss) + gfc_add_ss_to_loop (&loop, maskss); - gfc_add_ss_to_loop (&loop, arrayss); + gfc_add_ss_to_loop (&loop, arrayss); - /* Initialize the loop. */ - gfc_conv_ss_startstride (&loop); + /* Initialize the loop. */ + gfc_conv_ss_startstride (&loop); - /* The code generated can have more than one loop in sequence (see the - comment at the function header). This doesn't work well with the - scalarizer, which changes arrays' offset when the scalarization loops - are generated (see gfc_trans_preloop_setup). Fortunately, we can use - the scalarizer temporary code to handle multiple loops. Thus, we set - temp_dim here, we call gfc_mark_ss_chain_used with flag=3 later, and - we use gfc_trans_scalarized_loop_boundary even later to restore - offset. */ - loop.temp_dim = loop.dimen; - gfc_conv_loop_setup (&loop, &expr->where); + /* The code generated can have more than one loop in sequence (see the + comment at the function header). This doesn't work well with the + scalarizer, which changes arrays' offset when the scalarization loops + are generated (see gfc_trans_preloop_setup). Fortunately, we can use + the scalarizer temporary code to handle multiple loops. Thus, we set + temp_dim here, we call gfc_mark_ss_chain_used with flag=3 later, and + we use gfc_trans_scalarized_loop_boundary even later to restore + offset. */ + loop.temp_dim = loop.dimen; + gfc_conv_loop_setup (&loop, &expr->where); + + ploop = &loop; + } + + gcc_assert (reduction_dimensions == ploop->dimen); if (nonempty == NULL && maskss == NULL) { nonempty = logical_true_node; - for (int i = 0; i < loop.dimen; i++) + for (int i = 0; i < ploop->dimen; i++) { - if (!(loop.from[i] && loop.to[i])) + if (!(ploop->from[i] && ploop->to[i])) { nonempty = NULL; break; } tree tmp = fold_build2_loc (input_location, LE_EXPR, - logical_type_node, loop.from[i], - loop.to[i]); + logical_type_node, ploop->from[i], + ploop->to[i]); nonempty = fold_build2_loc (input_location, TRUTH_ANDIF_EXPR, logical_type_node, nonempty, tmp); @@ -5741,11 +5776,12 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) gfc_array_index_type, nonempty, gfc_index_one_node, gfc_index_zero_node); - for (int i = 0; i < loop.dimen; i++) - gfc_add_modify (&loop.pre, pos[i], init); + for (int i = 0; i < ploop->dimen; i++) + gfc_add_modify (&ploop->pre, pos[i], init); } else { + gcc_assert (!nested_loop); for (int i = 0; i < loop.dimen; i++) gfc_add_modify (&loop.pre, pos[i], gfc_index_zero_node); lab1 = gfc_build_label_decl (NULL_TREE); @@ -5756,24 +5792,29 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) /* An offset must be added to the loop counter to obtain the required position. */ - for (int i = 0; i < loop.dimen; i++) + for (int i = 0; i < ploop->dimen; i++) { - gcc_assert (loop.from[i]); + gcc_assert (ploop->from[i]); tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type, - gfc_index_one_node, loop.from[i]); - gfc_add_modify (&loop.pre, offset[i], tmp); + gfc_index_one_node, ploop->from[i]); + gfc_add_modify (&ploop->pre, offset[i], tmp); + } + + if (!nested_loop) + { + gfc_mark_ss_chain_used (arrayss, lab1 ? 3 : 1); + if (maskss) + gfc_mark_ss_chain_used (maskss, lab1 ? 3 : 1); } - gfc_mark_ss_chain_used (arrayss, lab1 ? 3 : 1); - if (maskss) - gfc_mark_ss_chain_used (maskss, lab1 ? 3 : 1); /* Generate the loop body. */ - gfc_start_scalarized_body (&loop, &body); + gfc_start_scalarized_body (ploop, &body); /* If we have a mask, only check this element if the mask is set. */ if (maskss) { + gcc_assert (!nested_loop); gfc_init_se (&maskse, NULL); gfc_copy_loopinfo_to_se (&maskse, &loop); maskse.ss = maskss; @@ -5786,9 +5827,10 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) gfc_init_block (&block); /* Compare with the current limit. */ - gfc_init_se (&arrayse, NULL); - gfc_copy_loopinfo_to_se (&arrayse, &loop); - arrayse.ss = arrayss; + gfc_init_se (&arrayse, base_se); + gfc_copy_loopinfo_to_se (&arrayse, ploop); + if (!nested_loop) + arrayse.ss = arrayss; gfc_conv_expr_val (&arrayse, arrayexpr); gfc_add_block_to_block (&block, &arrayse.pre); @@ -5803,6 +5845,8 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) stmtblock_t ifblock2; tree ifbody2; + gcc_assert (!nested_loop); + gfc_start_block (&ifblock2); for (int i = 0; i < loop.dimen; i++) { @@ -5819,12 +5863,12 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) gfc_add_expr_to_block (&block, tmp); } - for (int i = 0; i < loop.dimen; i++) + for (int i = 0; i < ploop->dimen; i++) { tmp = fold_build2_loc (input_location, PLUS_EXPR, TREE_TYPE (pos[i]), - loop.loopvar[i], offset[i]); + ploop->loopvar[i], offset[i]); gfc_add_modify (&ifblock, pos[i], tmp); - gfc_add_modify (&ifblock, idx[i], loop.loopvar[i]); + gfc_add_modify (&ifblock, idx[i], ploop->loopvar[i]); } gfc_add_modify (&ifblock, second_loop_entry, logical_true_node); @@ -5891,6 +5935,8 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) if (lab1) { + gcc_assert (!nested_loop); + for (int i = 0; i < loop.dimen; i++) loop.from[i] = fold_build3_loc (input_location, COND_EXPR, TREE_TYPE (loop.from[i]), @@ -6007,7 +6053,7 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) gfc_add_modify (&body, second_loop_entry, logical_false_node); } - gfc_trans_scalarizing_loops (&loop, &body); + gfc_trans_scalarizing_loops (ploop, &body); if (lab2) gfc_add_expr_to_block (&loop.pre, build1_v (LABEL_EXPR, lab2)); @@ -6017,6 +6063,8 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) { tree ifmask; + gcc_assert (!nested_loop); + gfc_init_se (&maskse, NULL); gfc_conv_expr_val (&maskse, maskexpr); gfc_add_block_to_block (&se->pre, &maskse.pre); @@ -6039,12 +6087,14 @@ gfc_conv_intrinsic_minmaxloc (gfc_se * se, gfc_expr * expr, enum tree_code op) } else { - gfc_add_block_to_block (&se->pre, &loop.pre); - gfc_add_block_to_block (&se->pre, &loop.post); + gfc_add_block_to_block (&se->pre, &ploop->pre); + gfc_add_block_to_block (&se->pre, &ploop->post); } - gfc_cleanup_loop (&loop); - if (expr->rank > 0) + if (!nested_loop) + gfc_cleanup_loop (&loop); + + if (!dim_present) { for (int i = 0; i < arrayexpr->rank; i++) { @@ -11805,7 +11855,29 @@ walk_inline_intrinsic_minmaxloc (gfc_ss *ss, gfc_expr *expr ATTRIBUTE_UNUSED) if (expr->rank == 0) return ss; - return gfc_get_array_ss (ss, expr, 1, GFC_SS_INTRINSIC); + gfc_actual_arglist *array_arg = expr->value.function.actual; + gfc_actual_arglist *dim_arg = array_arg->next; + + gfc_expr *array = array_arg->expr; + gfc_expr *dim = dim_arg->expr; + + if (dim == nullptr) + return gfc_get_array_ss (ss, expr, 1, GFC_SS_INTRINSIC); + + gfc_ss *tmp_ss = gfc_ss_terminator; + + gfc_ss *array_ss = gfc_walk_subexpr (tmp_ss, array); + gcc_assert (array_ss != tmp_ss); + + tmp_ss = array_ss; + + /* Move the dimension on which we will sum to a separate nested scalarization + chain, "hiding" that dimension from the outer scalarization. */ + int dim_val = mpz_get_si (dim->value.integer); + gfc_ss *tail = nest_loop_dimension (tmp_ss, dim_val - 1); + tail->next = ss; + + return array_ss; } @@ -11944,9 +12016,11 @@ gfc_inline_intrinsic_function_p (gfc_expr *expr) gfc_actual_arglist *array_arg = expr->value.function.actual; gfc_actual_arglist *dim_arg = array_arg->next; + gfc_actual_arglist *mask_arg = dim_arg->next; gfc_expr *array = array_arg->expr; gfc_expr *dim = dim_arg->expr; + gfc_expr *mask = mask_arg->expr; if (!(array->ts.type == BT_INTEGER || array->ts.type == BT_REAL)) @@ -11958,6 +12032,15 @@ gfc_inline_intrinsic_function_p (gfc_expr *expr) if (dim == nullptr) return true; + if (dim->expr_type != EXPR_CONSTANT) + return false; + + if (array->ts.type != BT_INTEGER) + return false; + + if (mask == nullptr) + return true; + return false; } diff --git a/gcc/testsuite/gfortran.dg/maxloc_bounds_1.f90 b/gcc/testsuite/gfortran.dg/maxloc_bounds_1.f90 index a107db2017a..992519fd477 100644 --- a/gcc/testsuite/gfortran.dg/maxloc_bounds_1.f90 +++ b/gcc/testsuite/gfortran.dg/maxloc_bounds_1.f90 @@ -1,6 +1,6 @@ ! { dg-do run } ! { dg-options "-fbounds-check" } -! { dg-shouldfail "Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2" } +! { dg-shouldfail "Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2|Array bound mismatch for dimension 1 of array 'res' .3/2." } program main integer(kind=4), allocatable :: f(:,:) integer(kind=4) :: res(3) @@ -10,5 +10,5 @@ program main res = maxloc(f,dim=1) write(line,fmt='(80I1)') res end program main -! { dg-output "Fortran runtime error: Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2" } +! { dg-output "Fortran runtime error: Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2|Array bound mismatch for dimension 1 of array 'res' .3/2." } diff --git a/gcc/testsuite/gfortran.dg/maxloc_bounds_2.f90 b/gcc/testsuite/gfortran.dg/maxloc_bounds_2.f90 index 39af3cb9fde..c5adb62e115 100644 --- a/gcc/testsuite/gfortran.dg/maxloc_bounds_2.f90 +++ b/gcc/testsuite/gfortran.dg/maxloc_bounds_2.f90 @@ -1,6 +1,6 @@ ! { dg-do run } ! { dg-options "-fbounds-check" } -! { dg-shouldfail "Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2" } +! { dg-shouldfail "Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2|Array bound mismatch for dimension 1 of array 'res' .3/2." } program main integer(kind=4), allocatable :: f(:,:) logical, allocatable :: m(:,:) @@ -12,5 +12,5 @@ program main res = maxloc(f,dim=1,mask=m) write(line,fmt='(80I1)') res end program main -! { dg-output "Fortran runtime error: Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2" } +! { dg-output "Fortran runtime error: Incorrect extent in return value of MAXLOC intrinsic in dimension 1: is 3, should be 2|Array bound mismatch for dimension 1 of array 'res' .3/2." } diff --git a/gcc/testsuite/gfortran.dg/maxloc_bounds_3.f90 b/gcc/testsuite/gfortran.dg/maxloc_bounds_3.f90 index 41df6a8d093..1c385051624 100644 --- a/gcc/testsuite/gfortran.dg/maxloc_bounds_3.f90 +++ b/gcc/testsuite/gfortran.dg/maxloc_bounds_3.f90 @@ -1,6 +1,6 @@ ! { dg-do run } ! { dg-options "-fbounds-check" } -! { dg-shouldfail "Incorrect extent in MASK argument of MAXLOC intrinsic in dimension 2: is 3, should be 2" } +! { dg-shouldfail "Incorrect extent in MASK argument of MAXLOC intrinsic in dimension 2: is 3, should be 2|Array bound mismatch for dimension 2 of array 'f' .2/3." } program main integer(kind=4), allocatable :: f(:,:) logical, allocatable :: m(:,:) @@ -12,5 +12,5 @@ program main res = maxloc(f,dim=1,mask=m) write(line,fmt='(80I1)') res end program main -! { dg-output "Fortran runtime error: Incorrect extent in MASK argument of MAXLOC intrinsic in dimension 2: is 3, should be 2" } +! { dg-output "Fortran runtime error: Incorrect extent in MASK argument of MAXLOC intrinsic in dimension 2: is 3, should be 2|Array bound mismatch for dimension 2 of array 'f' .2/3." } diff --git a/gcc/testsuite/gfortran.dg/minmaxloc_19.f90 b/gcc/testsuite/gfortran.dg/minmaxloc_19.f90 new file mode 100644 index 00000000000..c3dd075229f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/minmaxloc_19.f90 @@ -0,0 +1,182 @@ +! { dg-do compile } +! { dg-additional-options "-O -fdump-tree-original" } +! { dg-final { scan-tree-dump-not "gfortran_\[sm\]?minloc" "original" } } +! { dg-final { scan-tree-dump-not "gfortran_\[sm\]?maxloc" "original" } } +! +! PR fortran/90608 +! Check that all MINLOC and MAXLOC calls are inlined with optimizations, +! when ARRAY is of integral type, DIM is a constant, and MASK is absent. + +subroutine check_maxloc + implicit none + integer, parameter :: data60(*) = (/ 2, 5, 4, 6, 0, 9, 3, 5, 4, 4, & + 1, 7, 3, 2, 1, 2, 5, 4, 6, 0, & + 9, 3, 5, 4, 4, 1, 7, 3, 2, 1, & + 2, 5, 4, 6, 0, 9, 3, 5, 4, 4, & + 1, 7, 3, 2, 1, 2, 5, 4, 6, 0, & + 9, 3, 5, 4, 4, 1, 7, 3, 2, 1 /) + integer, parameter :: data1(*) = (/ 2, 3, 2, 3, & + 1, 2, 3, 2, & + 3, 1, 2, 3, & + 2, 3, 1, 2, & + 3, 2, 3, 1 /) + integer, parameter :: data2(*) = (/ 2, 1, 2, & + 3, 2, 3, & + 4, 3, 4, & + 2, 1, 2, & + 1, 2, 1 /) + integer, parameter :: data3(*) = (/ 5, 1, 5, & + 1, 2, 1, & + 2, 1, 2, & + 3, 2, 3 /) + call check_int_const_shape_rank_3 + call check_int_const_shape_empty_4 + call check_int_alloc_rank_3 + call check_int_alloc_empty_4 +contains + subroutine check_int_const_shape_rank_3() + integer :: a(3,4,5) + integer, allocatable :: r(:,:) + a = reshape(data60, shape(a)) + r = maxloc(a, dim=1) + if (any(shape(r) /= (/ 4, 5 /))) error stop 11 + if (any(r /= reshape(data1, (/ 4, 5 /)))) error stop 12 + r = maxloc(a, dim=2) + if (any(shape(r) /= (/ 3, 5 /))) error stop 13 + if (any(r /= reshape(data2, (/ 3, 5 /)))) error stop 14 + r = maxloc(a, dim=3) + if (any(shape(r) /= (/ 3, 4 /))) error stop 15 + if (any(r /= reshape(data3, (/ 3, 4 /)))) error stop 16 + end subroutine + subroutine check_int_const_shape_empty_4() + integer :: a(9,3,0,7) + integer, allocatable :: r(:,:,:) + a = reshape((/ integer:: /), shape(a)) + r = maxloc(a, dim=1) + if (any(shape(r) /= (/ 3, 0, 7 /))) error stop 21 + r = maxloc(a, dim=2) + if (any(shape(r) /= (/ 9, 0, 7 /))) error stop 22 + r = maxloc(a, dim=3) + if (any(shape(r) /= (/ 9, 3, 7 /))) error stop 23 + if (any(r /= 0)) error stop 24 + r = maxloc(a, dim=4) + if (any(shape(r) /= (/ 9, 3, 0 /))) error stop 25 + end subroutine + subroutine check_int_alloc_rank_3() + integer, allocatable :: a(:,:,:) + integer, allocatable :: r(:,:) + allocate(a(3,4,5)) + a(:,:,:) = reshape(data60, shape(a)) + r = maxloc(a, dim=1) + if (any(shape(r) /= (/ 4, 5 /))) error stop 31 + if (any(r /= reshape(data1, (/ 4, 5 /)))) error stop 32 + r = maxloc(a, dim=2) + if (any(shape(r) /= (/ 3, 5 /))) error stop 33 + if (any(r /= reshape(data2, (/ 3, 5 /)))) error stop 34 + r = maxloc(a, dim=3) + if (any(shape(r) /= (/ 3, 4 /))) error stop 35 + if (any(r /= reshape(data3, (/ 3, 4 /)))) error stop 36 + end subroutine + subroutine check_int_alloc_empty_4() + integer, allocatable :: a(:,:,:,:) + integer, allocatable :: r(:,:,:) + allocate(a(9,3,0,7)) + a(:,:,:,:) = reshape((/ integer:: /), shape(a)) + r = maxloc(a, dim=1) + if (any(shape(r) /= (/ 3, 0, 7 /))) error stop 41 + r = maxloc(a, dim=2) + if (any(shape(r) /= (/ 9, 0, 7 /))) error stop 42 + r = maxloc(a, dim=3) + if (any(shape(r) /= (/ 9, 3, 7 /))) error stop 43 + if (any(r /= 0)) error stop 44 + r = maxloc(a, dim=4) + if (any(shape(r) /= (/ 9, 3, 0 /))) error stop 45 + end subroutine +end subroutine + +subroutine check_minloc + implicit none + integer, parameter :: data60(*) = (/ 7, 4, 5, 3, 9, 0, 6, 4, 5, 5, & + 8, 2, 6, 7, 8, 7, 4, 5, 3, 9, & + 0, 6, 4, 5, 5, 8, 2, 6, 7, 8, & + 7, 4, 5, 3, 9, 0, 6, 4, 5, 5, & + 8, 2, 6, 7, 8, 7, 4, 5, 3, 9, & + 0, 6, 4, 5, 5, 8, 2, 6, 7, 8 /) + integer, parameter :: data1(*) = (/ 2, 3, 2, 3, & + 1, 2, 3, 2, & + 3, 1, 2, 3, & + 2, 3, 1, 2, & + 3, 2, 3, 1 /) + integer, parameter :: data2(*) = (/ 2, 1, 2, & + 3, 2, 3, & + 4, 3, 4, & + 2, 1, 2, & + 1, 2, 1 /) + integer, parameter :: data3(*) = (/ 5, 1, 5, & + 1, 2, 1, & + 2, 1, 2, & + 3, 2, 3 /) + call check_int_const_shape_rank_3 + call check_int_const_shape_empty_4 + call check_int_alloc_rank_3 + call check_int_alloc_empty_4 +contains + subroutine check_int_const_shape_rank_3() + integer :: a(3,4,5) + integer, allocatable :: r(:,:) + a = reshape(data60, shape(a)) + r = minloc(a, dim=1) + if (any(shape(r) /= (/ 4, 5 /))) error stop 111 + if (any(r /= reshape(data1, (/ 4, 5 /)))) error stop 112 + r = minloc(a, dim=2) + if (any(shape(r) /= (/ 3, 5 /))) error stop 113 + if (any(r /= reshape(data2, (/ 3, 5 /)))) error stop 114 + r = minloc(a, dim=3) + if (any(shape(r) /= (/ 3, 4 /))) error stop 115 + if (any(r /= reshape(data3, (/ 3, 4 /)))) error stop 116 + end subroutine + subroutine check_int_const_shape_empty_4() + integer :: a(9,3,0,7) + integer, allocatable :: r(:,:,:) + a = reshape((/ integer:: /), shape(a)) + r = minloc(a, dim=1) + if (any(shape(r) /= (/ 3, 0, 7 /))) error stop 121 + r = minloc(a, dim=2) + if (any(shape(r) /= (/ 9, 0, 7 /))) error stop 122 + r = minloc(a, dim=3) + if (any(shape(r) /= (/ 9, 3, 7 /))) error stop 123 + if (any(r /= 0)) error stop 124 + r = minloc(a, dim=4) + if (any(shape(r) /= (/ 9, 3, 0 /))) error stop 125 + end subroutine + subroutine check_int_alloc_rank_3() + integer, allocatable :: a(:,:,:) + integer, allocatable :: r(:,:) + allocate(a(3,4,5)) + a(:,:,:) = reshape(data60, shape(a)) + r = minloc(a, dim=1) + if (any(shape(r) /= (/ 4, 5 /))) error stop 131 + if (any(r /= reshape(data1, (/ 4, 5 /)))) error stop 132 + r = minloc(a, dim=2) + if (any(shape(r) /= (/ 3, 5 /))) error stop 133 + if (any(r /= reshape(data2, (/ 3, 5 /)))) error stop 134 + r = minloc(a, dim=3) + if (any(shape(r) /= (/ 3, 4 /))) error stop 135 + if (any(r /= reshape(data3, (/ 3, 4 /)))) error stop 136 + end subroutine + subroutine check_int_alloc_empty_4() + integer, allocatable :: a(:,:,:,:) + integer, allocatable :: r(:,:,:) + allocate(a(9,3,0,7)) + a(:,:,:,:) = reshape((/ integer:: /), shape(a)) + r = minloc(a, dim=1) + if (any(shape(r) /= (/ 3, 0, 7 /))) error stop 141 + r = minloc(a, dim=2) + if (any(shape(r) /= (/ 9, 0, 7 /))) error stop 142 + r = minloc(a, dim=3) + if (any(shape(r) /= (/ 9, 3, 7 /))) error stop 143 + if (any(r /= 0)) error stop 144 + r = minloc(a, dim=4) + if (any(shape(r) /= (/ 9, 3, 0 /))) error stop 145 + end subroutine +end subroutine