diff options
Diffstat (limited to 'gcc/omp-offload.c')
-rw-r--r-- | gcc/omp-offload.c | 195 |
1 files changed, 192 insertions, 3 deletions
diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c index c66f38b..32c2485 100644 --- a/gcc/omp-offload.c +++ b/gcc/omp-offload.c @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "cfgloop.h" +#include "context.h" /* Describe the OpenACC looping structure of a function. The entire function is held in a 'NULL' loop. */ @@ -124,6 +125,10 @@ add_decls_addresses_to_decl_constructor (vec<tree, va_gc> *v_decls, #endif && lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (it)); + /* See also omp_finish_file and output_offload_tables in lto-cgraph.c. */ + if (!in_lto_p && !symtab_node::get (it)) + continue; + tree size = NULL_TREE; if (is_var) size = fold_convert (const_ptr_type_node, DECL_SIZE_UNIT (it)); @@ -158,6 +163,166 @@ add_decls_addresses_to_decl_constructor (vec<tree, va_gc> *v_decls, } } +/* Return true if DECL is a function for which its references should be + analyzed. */ + +static bool +omp_declare_target_fn_p (tree decl) +{ + return (TREE_CODE (decl) == FUNCTION_DECL + && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)) + && !lookup_attribute ("omp declare target host", + DECL_ATTRIBUTES (decl)) + && (!flag_openacc + || oacc_get_fn_attrib (decl) == NULL_TREE)); +} + +/* Return true if DECL Is a variable for which its initializer references + should be analyzed. */ + +static bool +omp_declare_target_var_p (tree decl) +{ + return (VAR_P (decl) + && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)) + && !lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (decl))); +} + +/* Helper function for omp_discover_implicit_declare_target, called through + walk_tree. Mark referenced FUNCTION_DECLs implicitly as + declare target to. */ + +static tree +omp_discover_declare_target_tgt_fn_r (tree *tp, int *walk_subtrees, void *data) +{ + if (TREE_CODE (*tp) == FUNCTION_DECL + && !omp_declare_target_fn_p (*tp) + && !lookup_attribute ("omp declare target host", DECL_ATTRIBUTES (*tp))) + { + tree id = get_identifier ("omp declare target"); + if (!DECL_EXTERNAL (*tp) && DECL_SAVED_TREE (*tp)) + ((vec<tree> *) data)->safe_push (*tp); + DECL_ATTRIBUTES (*tp) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (*tp)); + symtab_node *node = symtab_node::get (*tp); + if (node != NULL) + { + node->offloadable = 1; + if (ENABLE_OFFLOADING) + g->have_offload = true; + } + } + else if (TYPE_P (*tp)) + *walk_subtrees = 0; + /* else if (TREE_CODE (*tp) == OMP_TARGET) + { + if (tree dev = omp_find_clause (OMP_TARGET_CLAUSES (*tp))) + if (OMP_DEVICE_ANCESTOR (dev)) + *walk_subtrees = 0; + } */ + return NULL_TREE; +} + +/* Similarly, but ignore references outside of OMP_TARGET regions. */ + +static tree +omp_discover_declare_target_fn_r (tree *tp, int *walk_subtrees, void *data) +{ + if (TREE_CODE (*tp) == OMP_TARGET) + { + /* And not OMP_DEVICE_ANCESTOR. */ + walk_tree_without_duplicates (&OMP_TARGET_BODY (*tp), + omp_discover_declare_target_tgt_fn_r, + data); + *walk_subtrees = 0; + } + else if (TYPE_P (*tp)) + *walk_subtrees = 0; + return NULL_TREE; +} + +/* Helper function for omp_discover_implicit_declare_target, called through + walk_tree. Mark referenced FUNCTION_DECLs implicitly as + declare target to. */ + +static tree +omp_discover_declare_target_var_r (tree *tp, int *walk_subtrees, void *data) +{ + if (TREE_CODE (*tp) == FUNCTION_DECL) + return omp_discover_declare_target_tgt_fn_r (tp, walk_subtrees, data); + else if (VAR_P (*tp) + && is_global_var (*tp) + && !omp_declare_target_var_p (*tp)) + { + tree id = get_identifier ("omp declare target"); + if (lookup_attribute ("omp declare target link", DECL_ATTRIBUTES (*tp))) + { + error_at (DECL_SOURCE_LOCATION (*tp), + "%qD specified both in declare target %<link%> and " + "implicitly in %<to%> clauses", *tp); + DECL_ATTRIBUTES (*tp) + = remove_attribute ("omp declare target link", DECL_ATTRIBUTES (*tp)); + } + if (TREE_STATIC (*tp) && DECL_INITIAL (*tp)) + ((vec<tree> *) data)->safe_push (*tp); + DECL_ATTRIBUTES (*tp) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (*tp)); + symtab_node *node = symtab_node::get (*tp); + if (node != NULL && !node->offloadable) + { + node->offloadable = 1; + if (ENABLE_OFFLOADING) + { + g->have_offload = true; + if (is_a <varpool_node *> (node)) + vec_safe_push (offload_vars, node->decl); + } + } + } + else if (TYPE_P (*tp)) + *walk_subtrees = 0; + return NULL_TREE; +} + +/* Perform the OpenMP implicit declare target to discovery. */ + +void +omp_discover_implicit_declare_target (void) +{ + cgraph_node *node; + varpool_node *vnode; + auto_vec<tree> worklist; + + FOR_EACH_DEFINED_FUNCTION (node) + if (DECL_SAVED_TREE (node->decl)) + { + if (omp_declare_target_fn_p (node->decl)) + worklist.safe_push (node->decl); + else if (DECL_STRUCT_FUNCTION (node->decl) + && DECL_STRUCT_FUNCTION (node->decl)->has_omp_target) + worklist.safe_push (node->decl); + } + FOR_EACH_STATIC_INITIALIZER (vnode) + if (omp_declare_target_var_p (vnode->decl)) + worklist.safe_push (vnode->decl); + while (!worklist.is_empty ()) + { + tree decl = worklist.pop (); + if (VAR_P (decl)) + walk_tree_without_duplicates (&DECL_INITIAL (decl), + omp_discover_declare_target_var_r, + &worklist); + else if (omp_declare_target_fn_p (decl)) + walk_tree_without_duplicates (&DECL_SAVED_TREE (decl), + omp_discover_declare_target_tgt_fn_r, + &worklist); + else + walk_tree_without_duplicates (&DECL_SAVED_TREE (decl), + omp_discover_declare_target_fn_r, + &worklist); + } +} + + /* Create new symbols containing (address, size) pairs for global variables, marked with "omp declare target" attribute, as well as addresses for the functions, which are outlined offloading regions. */ @@ -180,7 +345,7 @@ omp_finish_file (void) add_decls_addresses_to_decl_constructor (offload_vars, v_v); tree vars_decl_type = build_array_type_nelts (pointer_sized_int_node, - num_vars * 2); + vec_safe_length (v_v)); tree funcs_decl_type = build_array_type_nelts (pointer_sized_int_node, num_funcs); SET_TYPE_ALIGN (vars_decl_type, TYPE_ALIGN (pointer_sized_int_node)); @@ -215,11 +380,17 @@ omp_finish_file (void) for (unsigned i = 0; i < num_funcs; i++) { tree it = (*offload_funcs)[i]; + /* See also add_decls_addresses_to_decl_constructor + and output_offload_tables in lto-cgraph.c. */ + if (!in_lto_p && !symtab_node::get (it)) + continue; targetm.record_offload_symbol (it); } for (unsigned i = 0; i < num_vars; i++) { tree it = (*offload_vars)[i]; + if (!in_lto_p && !symtab_node::get (it)) + continue; #ifdef ACCEL_COMPILER if (DECL_HAS_VALUE_EXPR_P (it) && lookup_attribute ("omp declare target link", @@ -1905,12 +2076,28 @@ execute_omp_device_lower () bool regimplify = false; basic_block bb; gimple_stmt_iterator gsi; + bool calls_declare_variant_alt + = cgraph_node::get (cfun->decl)->calls_declare_variant_alt; FOR_EACH_BB_FN (bb, cfun) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); - if (!is_gimple_call (stmt) || !gimple_call_internal_p (stmt)) + if (!is_gimple_call (stmt)) continue; + if (!gimple_call_internal_p (stmt)) + { + if (calls_declare_variant_alt) + if (tree fndecl = gimple_call_fndecl (stmt)) + { + tree new_fndecl = omp_resolve_declare_variant (fndecl); + if (new_fndecl != fndecl) + { + gimple_call_set_fndecl (stmt, new_fndecl); + update_stmt (stmt); + } + } + continue; + } tree lhs = gimple_call_lhs (stmt), rhs = NULL_TREE; tree type = lhs ? TREE_TYPE (lhs) : integer_type_node; switch (gimple_call_internal_fn (stmt)) @@ -2004,7 +2191,9 @@ public: /* opt_pass methods: */ virtual bool gate (function *fun) { - return !(fun->curr_properties & PROP_gimple_lomp_dev); + return (!(fun->curr_properties & PROP_gimple_lomp_dev) + || (flag_openmp + && cgraph_node::get (fun->decl)->calls_declare_variant_alt)); } virtual unsigned int execute (function *) { |