From patchwork Fri Dec 10 17:35:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kwok Cheung Yeung X-Patchwork-Id: 48795 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 120E03857820 for ; Fri, 10 Dec 2021 17:35:56 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa1.mentor.iphmx.com (esa1.mentor.iphmx.com [68.232.129.153]) by sourceware.org (Postfix) with ESMTPS id 9D8B5385801D for ; Fri, 10 Dec 2021 17:35:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9D8B5385801D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: FDuwCnhhdXAOCWf2+Kd5ZMoXOi8gcb5A4P0p4TYI7z/6YCRdiKepsDHLu+Fw4xfGE2+RgyKGaJ TBY7OOkdBLRulZAFsN4z1lAjogM+hiByiw2uEF9HQvBnpOpjrf0eivi1M2Qz9eljw3PzetZDbV EUPvkQNNWUVTOAAI6rGfjxXzXPw5z3PdINpEXrh+ZagkgKmSiC71JepTZ5TuFKRJhlQjNBtUK+ 6tHsmIo1BaWkNmNoHaLH+649G22D93WBlmlIBFEBbqcwKpuRCwk6RaIPeTiI1RNcFOshlXjqpT hYBq57P5f4LuEMBMZwe1NSX6 X-IronPort-AV: E=Sophos;i="5.88,196,1635235200"; d="scan'208,223";a="72064202" Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 10 Dec 2021 09:35:36 -0800 IronPort-SDR: lNMoIvwLMr8qDxzqzGIDaAcIT0PUBuaGqIT0J0wg6XYwDQOWQt18y0R4yt2vKdyXzFAK4CJDJQ QrPyw4Wvyabd9D+P38X+8y8/OYtvWqisUOQbuFqa9WTbyjyXKr/s10Srn6rZp+FwKxklRTmRgP +N/5vJC9rBj03YPFrkX72FS8nIdszXclx/KCqK1XcmS+NkfpsyENMMoQc7cEwO44Is9pnVI3RN /N48TLdW0o96rMq7FU1mY6fImNvFXUchcJQZJcof7utpLg5JhA315XTptHulFh4P89RkAFv8Qz 9I0= Message-ID: <3570a7bc-fbf1-93f1-9a20-a788e4e707f2@codesourcery.com> Date: Fri, 10 Dec 2021 17:35:05 +0000 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Thunderbird/91.4.0 References: Subject: [PATCH 3/7] openmp: Add support for resolving metadirectives during parsing and Gimplification To: gcc-patches , Jakub Jelinek From: Kwok Cheung Yeung In-Reply-To: X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-10.mgc.mentorg.com (139.181.222.10) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This patch contains code to resolve metadirectives, either during parsing or Gimplification. The dynamic candidate selection algorithm from the OpenMP 5.1 spec is implemented in omp_get_dynamic_candidates in omp-general.c, which returns a vector containing information on the top-scoring candidate variants. The vector always consists of entries with dynamic selectors first, followed by a single entry with an all-static selector (which can be the default clause if all the other clauses are dynamic). If all selectors are static (i.e. OpenMP 5.0), then omp_get_dynamic_candidates will return a vector of at most length 1. If any part of the selectors in the candidate list cannot be resolved at the current stage of compilation, an empty list is returned. Note that it is possible to resolve metadirectives even with some selectors unresolvable as long as those selectors are not part of the candidate list. omp_context_selector_matches should always return 1 for dynamic selectors (since we can generate code to evaluate the condition at any time). omp_dynamic_cond, when given a selector, should return just the part of it that must be evaluated at run-time. Metadirectives are resolved in both tree and Gimple form by generating a sequence of if..then..else statements that evaluate the dynamic selector of each candidate returned from omp_get_dynamic_candidates in order, jumping to the directive body if true, to the next evaluation if not. Kwok From 65ee7342256db3c81cc6741ce2c96e36dd4a9ca6 Mon Sep 17 00:00:00 2001 From: Kwok Cheung Yeung Date: Mon, 6 Dec 2021 22:49:23 +0000 Subject: [PATCH 3/7] openmp: Add support for resolving metadirectives during parsing and Gimplification This adds support for resolving metadirectives according to the OpenMP 5.1 specification. The variants are sorted by score, then gathered into a list of dynamic replacement candidates. The metadirective is then expanded into a sequence of 'if..else' statements to test the dynamic selector and execute the variant if the selector is satisfied. If any of the selectors in the list are unresolvable, GCC will give up on resolving the metadirective and try again later. 2021-12-10 Kwok Cheung Yeung gcc/ * gimplify.c (expand_omp_metadirective): New. * omp-general.c: Include tree-pretty-print.h. (DELAY_METADIRECTIVES_AFTER_LTO): New macro. (omp_context_selector_matches): Delay resolution of selectors. Allow non-constant expressions. (omp_dynamic_cond): New. (omp_dynamic_selector_p): New. (sort_variant): New. (omp_get_dynamic_candidates): New. (omp_resolve_metadirective): New. (omp_resolve_metadirective): New. * omp-general.h (struct omp_metadirective_variant): New. (omp_resolve_metadirective): New prototype. gcc/c-family/ * c-omp.c (c_omp_expand_metadirective_r): New. (c_omp_expand_metadirective): New. --- gcc/c-family/c-omp.c | 45 ++++++++- gcc/gimplify.c | 72 +++++++++++++- gcc/omp-general.c | 232 ++++++++++++++++++++++++++++++++++++++++++- gcc/omp-general.h | 7 ++ 4 files changed, 346 insertions(+), 10 deletions(-) diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 9a7a6834f1b..fedaec566ee 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -3264,8 +3264,49 @@ c_omp_categorize_directive (const char *first, const char *second, return NULL; } +static tree +c_omp_expand_metadirective_r (vec &candidates, + hash_map &body_labels, + unsigned index) +{ + struct omp_metadirective_variant &candidate = candidates[index]; + tree if_block = push_stmt_list (); + if (candidate.directive != NULL_TREE) + add_stmt (candidate.directive); + if (candidate.body != NULL_TREE) + { + tree *label = body_labels.get (candidate.body); + if (label != NULL) + add_stmt (build1 (GOTO_EXPR, void_type_node, *label)); + else + { + tree body_label = create_artificial_label (UNKNOWN_LOCATION); + add_stmt (build1 (LABEL_EXPR, void_type_node, body_label)); + add_stmt (candidate.body); + body_labels.put (candidate.body, body_label); + } + } + if_block = pop_stmt_list (if_block); + + if (index == candidates.length () - 1) + return if_block; + + tree cond = candidate.selector; + gcc_assert (cond != NULL_TREE); + + tree else_block = c_omp_expand_metadirective_r (candidates, body_labels, + index + 1); + tree ret = push_stmt_list (); + tree stmt = build3 (COND_EXPR, void_type_node, cond, if_block, else_block); + add_stmt (stmt); + ret = pop_stmt_list (ret); + + return ret; +} + tree -c_omp_expand_metadirective (vec &) +c_omp_expand_metadirective (vec &candidates) { - return NULL_TREE; + hash_map body_labels; + return c_omp_expand_metadirective_r (candidates, body_labels, 0); } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index ed72162bb7f..5d9aa2c2145 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -14685,10 +14685,76 @@ gimplify_omp_ordered (tree expr, gimple_seq body) CANDIDATES. */ static enum gimplify_status -expand_omp_metadirective (vec &, - gimple_seq *) +expand_omp_metadirective (vec &candidates, + gimple_seq *pre_p) { - return GS_ERROR; + auto_vec selectors; + auto_vec directive_labels; + auto_vec directive_bodies; + tree body_label = NULL_TREE; + tree end_label = create_artificial_label (UNKNOWN_LOCATION); + + /* Construct bodies for each candidate. */ + for (unsigned i = 0; i < candidates.length(); i++) + { + struct omp_metadirective_variant &candidate = candidates[i]; + gimple_seq body = NULL; + + selectors.safe_push (candidate.selector); + directive_labels.safe_push (create_artificial_label (UNKNOWN_LOCATION)); + + gimplify_seq_add_stmt (&body, + gimple_build_label (directive_labels.last ())); + if (candidate.directive != NULL_TREE) + gimplify_stmt (&candidate.directive, &body); + if (candidate.body != NULL_TREE) + { + if (body_label != NULL_TREE) + gimplify_seq_add_stmt (&body, gimple_build_goto (body_label)); + else + { + body_label = create_artificial_label (UNKNOWN_LOCATION); + gimplify_seq_add_stmt (&body, gimple_build_label (body_label)); + gimplify_stmt (&candidate.body, &body); + } + } + + directive_bodies.safe_push (body); + } + + auto_vec cond_labels; + + cond_labels.safe_push (NULL_TREE); + for (unsigned i = 1; i < candidates.length () - 1; i++) + cond_labels.safe_push (create_artificial_label (UNKNOWN_LOCATION)); + if (candidates.length () > 1) + cond_labels.safe_push (directive_labels.last ()); + + /* Generate conditionals to test each dynamic selector in turn, executing + the directive candidate if successful. */ + for (unsigned i = 0; i < candidates.length () - 1; i++) + { + if (i != 0) + gimplify_seq_add_stmt (pre_p, gimple_build_label (cond_labels [i])); + + enum gimplify_status ret = gimplify_expr (&selectors[i], pre_p, NULL, + is_gimple_val, fb_rvalue); + if (ret == GS_ERROR || ret == GS_UNHANDLED) + return ret; + + gcond *cond_stmt + = gimple_build_cond_from_tree (selectors[i], directive_labels[i], + cond_labels[i + 1]); + + gimplify_seq_add_stmt (pre_p, cond_stmt); + gimplify_seq_add_seq (pre_p, directive_bodies[i]); + gimplify_seq_add_stmt (pre_p, gimple_build_goto (end_label)); + } + + gimplify_seq_add_seq (pre_p, directive_bodies.last ()); + gimplify_seq_add_stmt (pre_p, gimple_build_label (end_label)); + + return GS_ALL_DONE; } /* Gimplify an OMP_METADIRECTIVE construct. EXPR is the tree version. diff --git a/gcc/omp-general.c b/gcc/omp-general.c index 9926cfd9d5f..6340d1600a6 100644 --- a/gcc/omp-general.c +++ b/gcc/omp-general.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "data-streamer.h" #include "streamer-hooks.h" #include "opts.h" +#include "tree-pretty-print.h" enum omp_requires omp_requires_mask; @@ -1253,14 +1254,22 @@ omp_context_name_list_prop (tree prop) } } +#define DELAY_METADIRECTIVES_AFTER_LTO { \ + if (metadirective_p && !(cfun->curr_properties & PROP_gimple_lomp_dev)) \ + return -1; \ +} + /* Return 1 if context selector matches the current OpenMP context, 0 if it does not and -1 if it is unknown and need to be determined later. Some properties can be checked right away during parsing (this routine), others need to wait until the whole TU is parsed, others need to wait until - IPA, others until vectorization. */ + IPA, others until vectorization. + + Dynamic properties (which are evaluated at run-time) should always + return 1. */ int -omp_context_selector_matches (tree ctx, bool) +omp_context_selector_matches (tree ctx, bool metadirective_p) { int ret = 1; for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1)) @@ -1381,6 +1390,8 @@ omp_context_selector_matches (tree ctx, bool) const char *arch = omp_context_name_list_prop (t3); if (arch == NULL) return 0; + DELAY_METADIRECTIVES_AFTER_LTO; + int r = 0; if (targetm.omp.device_kind_arch_isa != NULL) r = targetm.omp.device_kind_arch_isa (omp_device_arch, @@ -1505,6 +1516,8 @@ omp_context_selector_matches (tree ctx, bool) #endif continue; } + DELAY_METADIRECTIVES_AFTER_LTO; + int r = 0; if (targetm.omp.device_kind_arch_isa != NULL) r = targetm.omp.device_kind_arch_isa (omp_device_kind, @@ -1544,6 +1557,8 @@ omp_context_selector_matches (tree ctx, bool) const char *isa = omp_context_name_list_prop (t3); if (isa == NULL) return 0; + DELAY_METADIRECTIVES_AFTER_LTO; + int r = 0; if (targetm.omp.device_kind_arch_isa != NULL) r = targetm.omp.device_kind_arch_isa (omp_device_isa, @@ -1595,6 +1610,12 @@ omp_context_selector_matches (tree ctx, bool) for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3)) if (TREE_PURPOSE (t3) == NULL_TREE) { + /* OpenMP 5.1 allows non-constant conditions for + metadirectives. */ + if (metadirective_p + && !tree_fits_shwi_p (TREE_VALUE (t3))) + break; + if (integer_zerop (TREE_VALUE (t3))) return 0; if (integer_nonzerop (TREE_VALUE (t3))) @@ -1610,6 +1631,8 @@ omp_context_selector_matches (tree ctx, bool) return ret; } +#undef DELAY_METADIRECTIVES_AFTER_LTO + /* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as in omp_context_selector_set_compare. */ @@ -1967,6 +1990,32 @@ omp_get_context_selector (tree ctx, const char *set, const char *sel) return NULL_TREE; } +/* Return a tree expression representing the dynamic part of the context + * selector CTX. */ + +static tree +omp_dynamic_cond (tree ctx) +{ + tree user = omp_get_context_selector (ctx, "user", "condition"); + if (user) + { + tree expr_list = TREE_VALUE (user); + + gcc_assert (TREE_PURPOSE (expr_list) == NULL_TREE); + return TREE_VALUE (expr_list); + } + return NULL_TREE; +} + +/* Return true iff the context selector CTX contains a dynamic element + that cannot be resolved at compile-time. */ + +static bool +omp_dynamic_selector_p (tree ctx) +{ + return omp_dynamic_cond (ctx) != NULL_TREE; +} + /* Compute *SCORE for context selector CTX. Return true if the score would be different depending on whether it is a declare simd clone or not. DECLARE_SIMD should be true for the case when it would be @@ -2624,16 +2673,189 @@ omp_lto_input_declare_variant_alt (lto_input_block *ib, cgraph_node *node, INSERT) = entryp; } +static int +sort_variant (const void * a, const void *b, void *) +{ + widest_int score1 = ((const struct omp_metadirective_variant *) a)->score; + widest_int score2 = ((const struct omp_metadirective_variant *) b)->score; + + if (score1 > score2) + return -1; + else if (score1 < score2) + return 1; + else + return 0; +} + +/* Return a vector of dynamic replacement candidates for the directive + candidates in ALL_VARIANTS. Return an empty vector if the metadirective + cannot be resolved. */ + +static vec +omp_get_dynamic_candidates (vec &all_variants) +{ + auto_vec variants; + struct omp_metadirective_variant default_variant; + bool default_found = false; + + for (unsigned int i = 0; i < all_variants.length (); i++) + { + struct omp_metadirective_variant variant = all_variants[i]; + + if (all_variants[i].selector == NULL_TREE) + { + default_found = true; + default_variant = all_variants[i]; + default_variant.score = 0; + default_variant.resolvable_p = true; + default_variant.dynamic_p = false; + continue; + } + + variant.resolvable_p = true; + + if (dump_file) + { + fprintf (dump_file, "Considering selector "); + print_generic_expr (dump_file, variant.selector); + fprintf (dump_file, " as candidate - "); + } + + switch (omp_context_selector_matches (variant.selector, true)) + { + case -1: + variant.resolvable_p = false; + if (dump_file) + fprintf (dump_file, "unresolvable"); + /* FALLTHRU */ + case 1: + /* TODO: Handle SIMD score?. */ + omp_context_compute_score (variant.selector, &variant.score, false); + variant.dynamic_p = omp_dynamic_selector_p (variant.selector); + variants.safe_push (variant); + break; + case 0: + if (dump_file) + fprintf (dump_file, "no match"); + break; + } + + if (dump_file) + fprintf (dump_file, "\n"); + } + + /* There must be one default variant. */ + gcc_assert (default_found); + + /* A context selector that is a strict subset of another context selector + has a score of zero. */ + for (unsigned int i = 0; i < variants.length (); i++) + for (unsigned int j = i + 1; j < variants.length (); j++) + { + int r = omp_context_selector_compare (variants[i].selector, + variants[j].selector); + if (r == -1) + { + /* variant1 is a strict subset of variant2. */ + variants[i].score = 0; + break; + } + else if (r == 1) + /* variant2 is a strict subset of variant1. */ + variants[j].score = 0; + } + + /* Sort the variants by decreasing score, preserving the original order + in case of a tie. */ + variants.stablesort (sort_variant, NULL); + + /* Add the default as a final choice. */ + variants.safe_push (default_variant); + + /* Build the dynamic candidate list. */ + for (unsigned i = 0; i < variants.length (); i++) + { + /* If one of the candidates is unresolvable, give up for now. */ + if (!variants[i].resolvable_p) + { + variants.truncate (0); + break; + } + + /* Replace the original selector with just the dynamic part. */ + variants[i].selector = omp_dynamic_cond (variants[i].selector); + + if (dump_file) + { + fprintf (dump_file, "Adding directive variant with "); + + if (variants[i].selector) + { + fprintf (dump_file, "selector "); + print_generic_expr (dump_file, variants[i].selector); + } + else + fprintf (dump_file, "default selector"); + + fprintf (dump_file, " as candidate.\n"); + } + + /* The last of the candidates is ended by a static selector. */ + if (!variants[i].dynamic_p) + { + variants.truncate (i + 1); + break; + } + } + + return variants.copy (); +} + /* Return a vector of dynamic replacement candidates for the metadirective statement in METADIRECTIVE. Return an empty vector if the metadirective cannot be resolved. */ vec -omp_resolve_metadirective (tree) +omp_resolve_metadirective (tree metadirective) +{ + auto_vec variants; + tree clause = OMP_METADIRECTIVE_CLAUSES (metadirective); + + while (clause) + { + struct omp_metadirective_variant variant; + + variant.selector = TREE_PURPOSE (clause); + variant.directive = TREE_PURPOSE (TREE_VALUE (clause)); + variant.body = TREE_VALUE (TREE_VALUE (clause)); + + variants.safe_push (variant); + clause = TREE_CHAIN (clause); + } + + return omp_get_dynamic_candidates (variants); +} + +/* Return a vector of dynamic replacement candidates for the metadirective + Gimple statement in GS. Return an empty vector if the metadirective + cannot be resolved. */ + +vec +omp_resolve_metadirective (gimple *gs) { - vec variants = {}; + auto_vec variants; + + for (unsigned i = 0; i < gimple_num_ops (gs); i++) + { + struct omp_metadirective_variant variant; + + variant.selector = gimple_op (gs, i); + variant.directive = gimple_omp_metadirective_label (gs, i); + + variants.safe_push (variant); + } - return variants; + return omp_get_dynamic_candidates (variants); } /* Encode an oacc launch argument. This matches the GOMP_LAUNCH_PACK diff --git a/gcc/omp-general.h b/gcc/omp-general.h index 8c6009e9854..5a0747b2791 100644 --- a/gcc/omp-general.h +++ b/gcc/omp-general.h @@ -93,6 +93,12 @@ struct omp_for_data struct omp_metadirective_variant { + widest_int score; + tree selector; + tree directive; + tree body; + bool dynamic_p : 1; + bool resolvable_p : 1; }; #define OACC_FN_ATTRIB "oacc function" @@ -119,6 +125,7 @@ extern int omp_context_selector_set_compare (const char *, tree, tree); extern tree omp_get_context_selector (tree, const char *, const char *); extern tree omp_resolve_declare_variant (tree); extern vec omp_resolve_metadirective (tree); +extern vec omp_resolve_metadirective (gimple *); extern tree oacc_launch_pack (unsigned code, tree device, unsigned op); extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims); extern void oacc_replace_fn_attrib (tree fn, tree dims);