[4/7] openmp: Add support for streaming metadirectives and resolving them after LTO
Commit Message
This patch adds support for streaming the Gimple metadirective
representation during LTO. An extra pass (also using
omp_get_dynamic_candidates) is also added to resolve metadirectives
after LTO, which is required for selectors that need to be resolved on
the accel compiler.
Kwok
From 85826d05e029571fd003dd629aa04ce3e17d9c71 Mon Sep 17 00:00:00 2001
From: Kwok Cheung Yeung <kcy@codesourcery.com>
Date: Mon, 6 Dec 2021 22:56:07 +0000
Subject: [PATCH 4/7] openmp: Add support for streaming metadirectives and
resolving them after LTO
This patch adds support for streaming metadirective Gimple statements during
LTO, and adds a metadirective expansion pass that runs after LTO. This is
required for metadirectives with selectors that can only be resolved from
within the accel compiler.
2021-12-10 Kwok Cheung Yeung <kcy@codesourcery.com>
gcc/
* Makefile.in (OBJS): Add omp-expand-metadirective.o.
* gimple-streamer-in.c (input_gimple_stmt): Add case for
GIMPLE_OMP_METADIRECTIVE. Handle metadirective labels.
* gimple-streamer-out.c (output_gimple_stmt): Likewise.
* omp-expand-metadirective.cc: New.
* passes.def: Add pass_omp_expand_metadirective.
* tree-pass.h (make_pass_omp_expand_metadirective): New prototype.
---
gcc/Makefile.in | 1 +
gcc/gimple-streamer-in.c | 10 ++
gcc/gimple-streamer-out.c | 6 +
gcc/omp-expand-metadirective.cc | 191 ++++++++++++++++++++++++++++++++
gcc/passes.def | 1 +
gcc/tree-pass.h | 1 +
6 files changed, 210 insertions(+)
create mode 100644 gcc/omp-expand-metadirective.cc
Comments
On Fri, Dec 10, 2021 at 05:36:20PM +0000, Kwok Cheung Yeung wrote:
> 2021-12-10 Kwok Cheung Yeung <kcy@codesourcery.com>
>
> gcc/
> * Makefile.in (OBJS): Add omp-expand-metadirective.o.
> * gimple-streamer-in.c (input_gimple_stmt): Add case for
> GIMPLE_OMP_METADIRECTIVE. Handle metadirective labels.
> * gimple-streamer-out.c (output_gimple_stmt): Likewise.
> * omp-expand-metadirective.cc: New.
> * passes.def: Add pass_omp_expand_metadirective.
> * tree-pass.h (make_pass_omp_expand_metadirective): New prototype.
> ---
> gcc/Makefile.in | 1 +
> gcc/gimple-streamer-in.c | 10 ++
> gcc/gimple-streamer-out.c | 6 +
> gcc/omp-expand-metadirective.cc | 191 ++++++++++++++++++++++++++++++++
> gcc/passes.def | 1 +
> gcc/tree-pass.h | 1 +
> 6 files changed, 210 insertions(+)
> create mode 100644 gcc/omp-expand-metadirective.cc
>
> @@ -151,6 +151,7 @@ input_gimple_stmt (class lto_input_block *ib, class data_in *data_in,
> case GIMPLE_COND:
> case GIMPLE_GOTO:
> case GIMPLE_DEBUG:
> + case GIMPLE_OMP_METADIRECTIVE:
> for (i = 0; i < num_ops; i++)
> {
> tree *opp, op = stream_read_tree (ib, data_in);
> @@ -188,6 +189,15 @@ input_gimple_stmt (class lto_input_block *ib, class data_in *data_in,
> else
> gimple_call_set_fntype (call_stmt, stream_read_tree (ib, data_in));
> }
> + if (gomp_metadirective *metadirective_stmt
> + = dyn_cast <gomp_metadirective*> (stmt))
> + {
> + gimple_alloc_omp_metadirective (metadirective_stmt);
> + for (i = 0; i < num_ops; i++)
> + gimple_omp_metadirective_set_label (metadirective_stmt, i,
> + stream_read_tree (ib,
> + data_in));
> + }
Ah, sorry for the comment about LTO streaming, here it is.
> --- /dev/null
> +++ b/gcc/omp-expand-metadirective.cc
> @@ -0,0 +1,191 @@
> +/* Expand an OpenMP metadirective.
> +
> + Copyright (C) 2021 Free Software Foundation, Inc.
We have 2022 now...
> +
Missing function comment.
> +static void
> +omp_expand_metadirective (function *fun, basic_block bb)
> +{
> + gimple *stmt = last_stmt (bb);
> + vec<struct omp_metadirective_variant> candidates
> + = omp_resolve_metadirective (stmt);
> +
> + /* This is the last chance for the metadirective to be resolved. */
> + if (candidates.is_empty ())
> + gcc_unreachable ();
gcc_assert (!candidates.is_empty ());
?
> + /* opt_pass methods: */
> + virtual bool gate (function *)
> + {
> + return (flag_openmp);
Useless ()s around it.
But much more importantly, I don't really like this to be a separate pass,
walking the whole IL once more is expensive, even when you restrict it
to just flag_openmp.
Late declare variant resolving is done in the (now a little bit misnamed)
pass_omp_device_lower.
The gate of that pass is right now:
return (!(fun->curr_properties & PROP_gimple_lomp_dev)
|| (flag_openmp
&& cgraph_node::get (fun->decl)->calls_declare_variant_alt));
so it would be nice to track (conservatively)
whether current function has any metadirectives
in it which aren't yet resolved (but perhaps the calls_declare_variant_alt
bit could be abused for that too) andin that case also deal with those.
You can surely gather them in the omp-offload.cc pass and then call
a function in your new file to handle that.
Jakub
@@ -1519,6 +1519,7 @@ OBJS = \
omp-oacc-kernels-decompose.o \
omp-oacc-neuter-broadcast.o \
omp-simd-clone.o \
+ omp-expand-metadirective.o \
opt-problem.o \
optabs.o \
optabs-libfuncs.o \
@@ -151,6 +151,7 @@ input_gimple_stmt (class lto_input_block *ib, class data_in *data_in,
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_DEBUG:
+ case GIMPLE_OMP_METADIRECTIVE:
for (i = 0; i < num_ops; i++)
{
tree *opp, op = stream_read_tree (ib, data_in);
@@ -188,6 +189,15 @@ input_gimple_stmt (class lto_input_block *ib, class data_in *data_in,
else
gimple_call_set_fntype (call_stmt, stream_read_tree (ib, data_in));
}
+ if (gomp_metadirective *metadirective_stmt
+ = dyn_cast <gomp_metadirective*> (stmt))
+ {
+ gimple_alloc_omp_metadirective (metadirective_stmt);
+ for (i = 0; i < num_ops; i++)
+ gimple_omp_metadirective_set_label (metadirective_stmt, i,
+ stream_read_tree (ib,
+ data_in));
+ }
break;
case GIMPLE_NOP:
@@ -127,6 +127,7 @@ output_gimple_stmt (struct output_block *ob, struct function *fn, gimple *stmt)
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_DEBUG:
+ case GIMPLE_OMP_METADIRECTIVE:
for (i = 0; i < gimple_num_ops (stmt); i++)
{
tree op = gimple_op (stmt, i);
@@ -169,6 +170,11 @@ output_gimple_stmt (struct output_block *ob, struct function *fn, gimple *stmt)
else
stream_write_tree (ob, gimple_call_fntype (stmt), true);
}
+ if (gimple_code (stmt) == GIMPLE_OMP_METADIRECTIVE)
+ for (i = 0; i < gimple_num_ops (stmt); i++)
+ stream_write_tree (ob, gimple_omp_metadirective_label (stmt, i),
+ true);
+
break;
case GIMPLE_NOP:
new file mode 100644
@@ -0,0 +1,191 @@
+/* Expand an OpenMP metadirective.
+
+ Copyright (C) 2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "target.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "fold-const.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "gomp-constants.h"
+#include "omp-general.h"
+#include "diagnostic-core.h"
+#include "tree-cfg.h"
+#include "cfganal.h"
+#include "ssa.h"
+#include "tree-into-ssa.h"
+#include "cfghooks.h"
+
+static void
+omp_expand_metadirective (function *fun, basic_block bb)
+{
+ gimple *stmt = last_stmt (bb);
+ vec<struct omp_metadirective_variant> candidates
+ = omp_resolve_metadirective (stmt);
+
+ /* This is the last chance for the metadirective to be resolved. */
+ if (candidates.is_empty ())
+ gcc_unreachable ();
+
+ auto_vec<tree> labels;
+
+ for (unsigned int i = 0; i < candidates.length (); i++)
+ labels.safe_push (candidates[i].directive);
+
+ /* Delete BBs for all variants not in the candidate list. */
+ for (unsigned i = 0; i < gimple_num_ops (stmt); i++)
+ {
+ tree label = gimple_omp_metadirective_label (stmt, i);
+ if (!labels.contains (label))
+ {
+ edge e = find_edge (bb, label_to_block (fun, label));
+ remove_edge_and_dominated_blocks (e);
+ }
+ }
+
+ /* Remove the metadirective statement. */
+ gimple_stmt_iterator gsi = gsi_last_bb (bb);
+ gsi_remove (&gsi, true);
+
+ if (candidates.length () == 1)
+ {
+ /* Special case if there is only one selector - there should be one
+ remaining edge from BB to the selected variant. */
+ edge e = find_edge (bb, label_to_block (fun,
+ candidates.last ().directive));
+ e->flags |= EDGE_FALLTHRU;
+
+ return;
+ }
+
+ basic_block cur_bb = bb;
+
+ /* For each candidate, create a conditional that checks the dynamic
+ condition, branching to the candidate directive if true, to the
+ next candidate check if false. */
+ for (unsigned i = 0; i < candidates.length () - 1; i++)
+ {
+ basic_block next_bb = NULL;
+ gcond *cond_stmt = gimple_build_cond_from_tree (candidates[i].selector,
+ NULL_TREE, NULL_TREE);
+ gsi = gsi_last_bb (cur_bb);
+ gsi_insert_seq_after (&gsi, cond_stmt, GSI_NEW_STMT);
+
+ if (i < candidates.length () - 2)
+ {
+ edge e_false = split_block (cur_bb, cond_stmt);
+ e_false->flags &= ~EDGE_FALLTHRU;
+ e_false->flags |= EDGE_FALSE_VALUE;
+ e_false->probability = profile_probability::uninitialized ();
+
+ next_bb = e_false->dest;
+ }
+
+ /* Redirect the source of the edge from BB to the candidate directive
+ to the conditional. Reusing the edge avoids disturbing phi nodes in
+ the destination BB. */
+ edge e = find_edge (bb, label_to_block (fun, candidates[i].directive));
+ redirect_edge_pred (e, cur_bb);
+ e->flags |= EDGE_TRUE_VALUE;
+
+ if (next_bb)
+ cur_bb = next_bb;
+ }
+
+ /* The last of the candidates is always static. */
+ edge e = find_edge (cur_bb, label_to_block (fun,
+ candidates.last ().directive));
+ e->flags |= EDGE_FALSE_VALUE;
+}
+
+namespace {
+
+const pass_data pass_data_omp_expand_metadirective =
+{
+ GIMPLE_PASS, /* type */
+ "omp_expand_metadirective", /* name */
+ OPTGROUP_OMP, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ PROP_gimple_lcf, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa | TODO_cleanup_cfg, /* todo_flags_finish */
+};
+
+class pass_omp_expand_metadirective : public gimple_opt_pass
+{
+public:
+ pass_omp_expand_metadirective (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_omp_expand_metadirective, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return (flag_openmp);
+ }
+
+ virtual unsigned int execute (function *fun);
+}; // class pass_omp_oacc_kernels_decompose
+
+unsigned int
+pass_omp_expand_metadirective::execute (function *fun)
+{
+ basic_block bb;
+ auto_vec<basic_block> metadirective_bbs;
+
+ FOR_EACH_BB_FN (bb, fun)
+ {
+ gimple *stmt = last_stmt (bb);
+ if (stmt && is_a<gomp_metadirective *> (stmt))
+ metadirective_bbs.safe_push (bb);
+ }
+
+ if (metadirective_bbs.is_empty ())
+ return 0;
+
+ calculate_dominance_info (CDI_DOMINATORS);
+
+ for (unsigned i = 0; i < metadirective_bbs.length (); i++)
+ omp_expand_metadirective (fun, metadirective_bbs[i]);
+
+ free_dominance_info (fun, CDI_DOMINATORS);
+ mark_virtual_operands_for_renaming (fun);
+
+ return 0;
+}
+
+} // anon namespace
+
+
+gimple_opt_pass *
+make_pass_omp_expand_metadirective (gcc::context *ctxt)
+{
+ return new pass_omp_expand_metadirective (ctxt);
+}
@@ -189,6 +189,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_oacc_device_lower);
NEXT_PASS (pass_omp_device_lower);
NEXT_PASS (pass_omp_target_link);
+ NEXT_PASS (pass_omp_expand_metadirective);
NEXT_PASS (pass_adjust_alignment);
NEXT_PASS (pass_all_optimizations);
PUSH_INSERT_PASSES_WITHIN (pass_all_optimizations)
@@ -422,6 +422,7 @@ extern gimple_opt_pass *make_pass_lower_switch_O0 (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_vector (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_vector_ssa (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_omp_oacc_kernels_decompose (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_omp_expand_metadirective (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_lower_omp (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_diagnose_omp_blocks (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_expand_omp (gcc::context *ctxt);