https://gcc.gnu.org/g:14568217c74206c9c5d033050fba6fe2ab57bb05
commit 14568217c74206c9c5d033050fba6fe2ab57bb05 Author: Thomas Schwinge <tschwi...@baylibre.com> Date: Fri Apr 25 16:39:39 2025 +0200 Revert 'OpenMP: Constructors and destructors for "declare target" static aggregates' ... in preparation of cherry-picking the upstream trunk changes. This reverts commit 9127b4db9c58f48e0b47816d64e22c21404136b3. gcc/ Revert: 2023-05-12 Julian Brown <jul...@codesourcery.com> * omp-builtins.def (BUILT_IN_OMP_IS_INITIAL_DEVICE): New builtin. * tree.cc (get_file_function_name): Support names for on-target constructor/destructor functions. gcc/cp/ Revert: 2023-05-12 Julian Brown <jul...@codesourcery.com> * decl2.cc (tree-inline.h): Include. (static_init_fini_fns): Bump to four entries. Update comment. (start_objects, start_partial_init_fini_fn): Add 'omp_target' parameter. Support "declare target" decls. Update forward declaration. (emit_partial_init_fini_fn): Add 'host_fn' parameter. Return tree for the created function. Support "declare target". (OMP_SSDF_IDENTIFIER): New macro. (partition_vars_for_init_fini): Support partitioning "declare target" variables also. (generate_ctor_or_dtor_function): Add 'omp_target' parameter. Support "declare target" decls. (c_parse_final_cleanups): Support constructors/destructors on OpenMP offload targets. libgomp/ Revert: 2023-05-12 Julian Brown <jul...@codesourcery.com> * testsuite/libgomp.c++/static-aggr-constructor-destructor-1.C: New test. * testsuite/libgomp.c++/static-aggr-constructor-destructor-2.C: New test. * testsuite/libgomp.c++/static-aggr-constructor-destructor-3.C: New test. Diff: --- gcc/ChangeLog.omp | 9 + gcc/cp/ChangeLog.omp | 19 ++ gcc/cp/decl2.cc | 241 ++++----------------- gcc/omp-builtins.def | 2 - gcc/tree.cc | 6 +- libgomp/ChangeLog.omp | 12 + .../static-aggr-constructor-destructor-1.C | 28 --- .../static-aggr-constructor-destructor-2.C | 31 --- .../static-aggr-constructor-destructor-3.C | 36 --- 9 files changed, 80 insertions(+), 304 deletions(-) diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp index 2ec578ce6d0a..58bf5d9515a1 100644 --- a/gcc/ChangeLog.omp +++ b/gcc/ChangeLog.omp @@ -1,3 +1,12 @@ +2025-04-25 Thomas Schwinge <tschwi...@baylibre.com> + + Revert: + 2023-05-12 Julian Brown <jul...@codesourcery.com> + + * omp-builtins.def (BUILT_IN_OMP_IS_INITIAL_DEVICE): New builtin. + * tree.cc (get_file_function_name): Support names for on-target + constructor/destructor functions. + 2025-04-17 Kwok Cheung Yeung <kcye...@baylibre.com> * langhooks-def.h (lhd_omp_deep_mapping): Add new argument. diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp index 80b4344a1b5b..a689be1e3f89 100644 --- a/gcc/cp/ChangeLog.omp +++ b/gcc/cp/ChangeLog.omp @@ -1,3 +1,22 @@ +2025-04-25 Thomas Schwinge <tschwi...@baylibre.com> + + Revert: + 2023-05-12 Julian Brown <jul...@codesourcery.com> + + * decl2.cc (tree-inline.h): Include. + (static_init_fini_fns): Bump to four entries. Update comment. + (start_objects, start_partial_init_fini_fn): Add 'omp_target' + parameter. Support "declare target" decls. Update forward declaration. + (emit_partial_init_fini_fn): Add 'host_fn' parameter. Return tree for + the created function. Support "declare target". + (OMP_SSDF_IDENTIFIER): New macro. + (partition_vars_for_init_fini): Support partitioning "declare target" + variables also. + (generate_ctor_or_dtor_function): Add 'omp_target' parameter. Support + "declare target" decls. + (c_parse_final_cleanups): Support constructors/destructors on OpenMP + offload targets. + 2025-04-17 Kwok Cheung Yeung <kcye...@baylibre.com> * parser.cc (cp_parser_omp_clause_map): Apply iterator to push and diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 56b222412b86..b30003cccd9f 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -50,22 +50,20 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "optabs-query.h" #include "omp-general.h" -#include "tree-inline.h" /* Id for dumping the raw trees. */ int raw_dump_id; extern cpp_reader *parse_in; -static tree start_objects (bool, unsigned, bool, bool); +static tree start_objects (bool, unsigned, bool); static tree finish_objects (bool, unsigned, tree, bool = true); -static tree start_partial_init_fini_fn (bool, unsigned, unsigned, bool); +static tree start_partial_init_fini_fn (bool, unsigned, unsigned); static void finish_partial_init_fini_fn (tree); -static tree emit_partial_init_fini_fn (bool, unsigned, tree, - unsigned, location_t, tree); +static void emit_partial_init_fini_fn (bool, unsigned, tree, + unsigned, location_t); static void one_static_initialization_or_destruction (bool, tree, tree); -static void generate_ctor_or_dtor_function (bool, unsigned, tree, location_t, - bool); +static void generate_ctor_or_dtor_function (bool, unsigned, tree, location_t); static tree prune_vars_needing_no_initialization (tree *); static void write_out_vars (tree); static void import_export_class (tree); @@ -167,10 +165,9 @@ struct priority_map_traits typedef hash_map<unsigned/*Priority*/, tree/*List*/, priority_map_traits> priority_map_t; -/* Two pairs of such hash tables, for the host and an OpenMP offload device. - Each pair has one priority map for fini and one for init. The fini tables - are only ever used when !cxa_atexit. */ -static GTY(()) priority_map_t *static_init_fini_fns[4]; +/* A pair of such hash tables, indexed by initp -- one for fini and + one for init. The fini table is only ever used when !cxa_atexit. */ +static GTY(()) priority_map_t *static_init_fini_fns[2]; /* Nonzero if we're done parsing and into end-of-file activities. 2 if all templates have been instantiated. @@ -4026,8 +4023,7 @@ generate_tls_wrapper (tree fn) /* Start a global constructor or destructor function. */ static tree -start_objects (bool initp, unsigned priority, bool has_body, - bool omp_target = false) +start_objects (bool initp, unsigned priority, bool has_body) { bool default_init = initp && priority == DEFAULT_INIT_PRIORITY; bool is_module_init = default_init && module_global_init_needed (); @@ -4041,15 +4037,7 @@ start_objects (bool initp, unsigned priority, bool has_body, /* We use `I' to indicate initialization and `D' to indicate destruction. */ - unsigned len; - if (omp_target) - /* Use "off_" signifying "offload" here. The name must be distinct - from the non-offload case. The format of the name is scanned in - tree.cc/get_file_function_name, so stick to the same length for - both name variants. */ - len = sprintf (type, "off_%c", initp ? 'I' : 'D'); - else - len = sprintf (type, "sub_%c", initp ? 'I' : 'D'); + unsigned len = sprintf (type, "sub_%c", initp ? 'I' : 'D'); if (priority != DEFAULT_INIT_PRIORITY) { char joiner = '_'; @@ -4064,17 +4052,6 @@ start_objects (bool initp, unsigned priority, bool has_body, tree fntype = build_function_type (void_type_node, void_list_node); tree fndecl = build_lang_decl (FUNCTION_DECL, name, fntype); - - if (omp_target) - { - DECL_ATTRIBUTES (fndecl) - = tree_cons (get_identifier ("omp declare target"), NULL_TREE, - DECL_ATTRIBUTES (fndecl)); - DECL_ATTRIBUTES (fndecl) - = tree_cons (get_identifier ("omp declare target nohost"), NULL_TREE, - DECL_ATTRIBUTES (fndecl)); - } - DECL_CONTEXT (fndecl) = FROB_CONTEXT (global_namespace); if (is_module_init) { @@ -4159,63 +4136,34 @@ finish_objects (bool initp, unsigned priority, tree body, bool startp) /* The name of the function we create to handle initializations and destructions for objects with static storage duration. */ #define SSDF_IDENTIFIER "__static_initialization_and_destruction" -#define OMP_SSDF_IDENTIFIER "__omp_target_static_init_and_destruction" /* Begins the generation of the function that will handle all initialization or destruction of objects with static storage duration at PRIORITY. - It is assumed that this function will be called once for the host, and once - for an OpenMP offload target. */ + It is assumed that this function will only be called once. */ static tree -start_partial_init_fini_fn (bool initp, unsigned priority, unsigned count, - bool omp_target) +start_partial_init_fini_fn (bool initp, unsigned priority, unsigned count) { - tree name; + char id[sizeof (SSDF_IDENTIFIER) + 1 /* '\0' */ + 32]; - if (omp_target) - { - char id[sizeof (OMP_SSDF_IDENTIFIER) + 1 /* \0 */ + 32]; - - /* Create the identifier for this function. It will be of the form - OMP_SSDF_IDENTIFIER_<number>. */ - sprintf (id, "%s_%u", OMP_SSDF_IDENTIFIER, count); - name = get_identifier (id); - } - else - { - char id[sizeof (SSDF_IDENTIFIER) + 1 /* '\0' */ + 32]; - /* Create the identifier for this function. It will be of the form - SSDF_IDENTIFIER_<number>. */ - sprintf (id, "%s_%u", SSDF_IDENTIFIER, count); - name = get_identifier (id); - } + /* Create the identifier for this function. It will be of the form + SSDF_IDENTIFIER_<number>. */ + sprintf (id, "%s_%u", SSDF_IDENTIFIER, count); tree type = build_function_type (void_type_node, void_list_node); /* Create the FUNCTION_DECL itself. */ - tree fn = build_lang_decl (FUNCTION_DECL, name, type); + tree fn = build_lang_decl (FUNCTION_DECL, get_identifier (id), type); TREE_PUBLIC (fn) = 0; DECL_ARTIFICIAL (fn) = 1; - if (omp_target) - { - DECL_ATTRIBUTES (fn) - = tree_cons (get_identifier ("omp declare target"), NULL_TREE, - DECL_ATTRIBUTES (fn)); - DECL_ATTRIBUTES (fn) - = tree_cons (get_identifier ("omp declare target nohost"), NULL_TREE, - DECL_ATTRIBUTES (fn)); - } - - int idx = initp + 2 * omp_target; - /* Put this function in the list of functions to be called from the static constructors and destructors. */ - if (!static_init_fini_fns[idx]) - static_init_fini_fns[idx] = priority_map_t::create_ggc (); - auto &slot = static_init_fini_fns[idx]->get_or_insert (priority); + if (!static_init_fini_fns[initp]) + static_init_fini_fns[initp] = priority_map_t::create_ggc (); + auto &slot = static_init_fini_fns[initp]->get_or_insert (priority); slot = tree_cons (fn, NULL_TREE, slot); /* Put the function in the global scope. */ @@ -4411,76 +4359,22 @@ one_static_initialization_or_destruction (bool initp, tree decl, tree init) a TREE_LIST of VAR_DECL with static storage duration. Whether initialization or destruction is performed is specified by INITP. */ -static tree +static void emit_partial_init_fini_fn (bool initp, unsigned priority, tree vars, - unsigned counter, location_t locus, tree host_fn) + unsigned counter, location_t locus) { input_location = locus; - bool omp_target = (host_fn != NULL_TREE); - tree body = start_partial_init_fini_fn (initp, priority, counter, omp_target); - tree fndecl = current_function_decl; - - tree nonhost_if_stmt = NULL_TREE; - if (omp_target) - { - nonhost_if_stmt = begin_if_stmt (); - /* We add an "omp declare target nohost" attribute, but (for - now) we still get a copy of the constructor/destructor on - the host. Make sure it does nothing unless we're on the - target device. */ - tree fn - = builtin_decl_explicit (BUILT_IN_OMP_IS_INITIAL_DEVICE); - tree initial_dev = build_call_expr (fn, 0); - tree target_dev_p - = cp_build_binary_op (input_location, NE_EXPR, initial_dev, - build_int_cst (NULL_TREE, 1), - tf_warning_or_error); - finish_if_stmt_cond (target_dev_p, nonhost_if_stmt); - } + tree body = start_partial_init_fini_fn (initp, priority, counter); for (tree node = vars; node; node = TREE_CHAIN (node)) - { - tree decl = TREE_VALUE (node); - tree init = TREE_PURPOSE (node); - /* We will emit 'init' twice, and it is modified in-place during - gimplification. Make a copy here. */ - if (omp_target) - { - /* We've already emitted INIT in the host version of the ctor/dtor - function. We need to deep-copy it (including new versions of - local variables introduced, etc.) for use in the target - ctor/dtor function. */ - copy_body_data id; - hash_map<tree, tree> decl_map; - memset (&id, 0, sizeof (id)); - id.src_fn = host_fn; - id.dst_fn = current_function_decl; - id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn); - id.decl_map = &decl_map; - id.copy_decl = copy_decl_no_change; - id.transform_call_graph_edges = CB_CGE_DUPLICATE; - id.transform_new_cfg = true; - id.transform_return_to_modify = false; - id.eh_lp_nr = 0; - walk_tree (&init, copy_tree_body_r, &id, NULL); - } - /* Do one initialization or destruction. */ - one_static_initialization_or_destruction (initp, decl, init); - } - - if (omp_target) - { - /* Finish up nonhost if-stmt body. */ - finish_then_clause (nonhost_if_stmt); - finish_if_stmt (nonhost_if_stmt); - } + /* Do one initialization or destruction. */ + one_static_initialization_or_destruction (initp, TREE_VALUE (node), + TREE_PURPOSE (node)); /* Finish up the static storage duration function for this round. */ input_location = locus; finish_partial_init_fini_fn (body); - - return fndecl; } /* VARS is a list of variables with static storage duration which may @@ -4543,7 +4437,7 @@ prune_vars_needing_no_initialization (tree *vars) This reverses the variable ordering. */ void -partition_vars_for_init_fini (tree var_list, priority_map_t *(&parts)[4]) +partition_vars_for_init_fini (tree var_list, priority_map_t *(&parts)[2]) { for (auto node = var_list; node; node = TREE_CHAIN (node)) { @@ -4569,30 +4463,6 @@ partition_vars_for_init_fini (tree var_list, priority_map_t *(&parts)[4]) auto &slot = parts[false]->get_or_insert (priority); slot = tree_cons (NULL_TREE, decl, slot); } - - if (flag_openmp - && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))) - { - priority_map_t **omp_parts = parts + 2; - - if (init || (flag_use_cxa_atexit && has_cleanup)) - { - // Add to initialization list. - if (!omp_parts[true]) - omp_parts[true] = priority_map_t::create_ggc (); - auto &slot = omp_parts[true]->get_or_insert (priority); - slot = tree_cons (init, decl, slot); - } - - if (!flag_use_cxa_atexit && has_cleanup) - { - // Add to finalization list. - if (!omp_parts[false]) - omp_parts[false] = priority_map_t::create_ggc (); - auto &slot = omp_parts[false]->get_or_insert (priority); - slot = tree_cons (NULL_TREE, decl, slot); - } - } } } @@ -4620,10 +4490,10 @@ write_out_vars (tree vars) static void generate_ctor_or_dtor_function (bool initp, unsigned priority, - tree fns, location_t locus, bool omp_target) + tree fns, location_t locus) { input_location = locus; - tree body = start_objects (initp, priority, bool (fns), omp_target); + tree body = start_objects (initp, priority, bool (fns)); if (fns) { @@ -5296,7 +5166,7 @@ c_parse_final_cleanups (void) auto_vec<tree> consteval_vtables; int retries = 0; - unsigned ssdf_count = 0, omp_ssdf_count = 0; + unsigned ssdf_count = 0; for (bool reconsider = true; reconsider; retries++) { reconsider = false; @@ -5359,9 +5229,8 @@ c_parse_final_cleanups (void) write_out_vars (vars); function_depth++; // Disable GC - priority_map_t *parts[4] = {nullptr, nullptr, nullptr, nullptr}; + priority_map_t *parts[2] = {nullptr, nullptr}; partition_vars_for_init_fini (vars, parts); - tree host_init_fini[2] = { NULL_TREE, NULL_TREE }; for (unsigned initp = 2; initp--;) if (parts[initp]) @@ -5372,32 +5241,10 @@ c_parse_final_cleanups (void) // Partitioning kept the vars in reverse order. // We only want that for dtors. list = nreverse (list); - host_init_fini[initp] - = emit_partial_init_fini_fn (initp, iter.first, list, - ssdf_count++, - locus_at_end_of_parsing, - NULL_TREE); + emit_partial_init_fini_fn (initp, iter.first, list, + ssdf_count++, + locus_at_end_of_parsing); } - - if (flag_openmp) - { - priority_map_t **omp_parts = parts + 2; - for (unsigned initp = 2; initp--;) - if (omp_parts[initp]) - for (auto iter : *omp_parts[initp]) - { - auto list = iter.second; - if (initp) - // Partitioning kept the vars in reverse order. - // We only want that for dtors. - list = nreverse (list); - emit_partial_init_fini_fn (initp, iter.first, list, - omp_ssdf_count++, - locus_at_end_of_parsing, - host_init_fini[initp]); - } - } - function_depth--; // Re-enable GC /* All those initializations and finalizations might cause @@ -5568,10 +5415,6 @@ c_parse_final_cleanups (void) for (auto iter : *static_init_fini_fns[true]) iter.second = nreverse (iter.second); - if (flag_openmp && static_init_fini_fns[2 + true]) - for (auto iter : *static_init_fini_fns[2 + true]) - iter.second = nreverse (iter.second); - /* Now we've instantiated all templates. Now we can escalate the functions we squirreled away earlier. */ process_and_check_pending_immediate_escalating_fns (); @@ -5590,7 +5433,7 @@ c_parse_final_cleanups (void) { input_location = locus_at_end_of_parsing; tree body = start_partial_init_fini_fn (true, DEFAULT_INIT_PRIORITY, - ssdf_count++, false); + ssdf_count++); /* For Objective-C++, we may need to initialize metadata found in this module. This must be done _before_ any other static initializations. */ @@ -5609,26 +5452,18 @@ c_parse_final_cleanups (void) static_init_fini_fns[true] = priority_map_t::create_ggc (); if (static_init_fini_fns[true]->get_or_insert (DEFAULT_INIT_PRIORITY)) has_module_inits = true; - - if (flag_openmp) - { - if (!static_init_fini_fns[2 + true]) - static_init_fini_fns[2 + true] = priority_map_t::create_ggc (); - static_init_fini_fns[2 + true]->get_or_insert (DEFAULT_INIT_PRIORITY); - } } /* Generate initialization and destruction functions for all priorities for which they are required. They have C-language linkage. */ push_lang_context (lang_name_c); - for (unsigned initp = 4; initp--;) + for (unsigned initp = 2; initp--;) if (static_init_fini_fns[initp]) { for (auto iter : *static_init_fini_fns[initp]) - generate_ctor_or_dtor_function (initp & 1, iter.first, iter.second, - locus_at_end_of_parsing, - (initp & 2) != 0); + generate_ctor_or_dtor_function (initp, iter.first, iter.second, + locus_at_end_of_parsing); static_init_fini_fns[initp] = nullptr; } pop_lang_context (); diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 608c9af315ed..840b43d482e4 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -68,8 +68,6 @@ DEF_GOACC_BUILTIN_ONLY (BUILT_IN_GOACC_SINGLE_COPY_START, "GOACC_single_copy_sta DEF_GOACC_BUILTIN_ONLY (BUILT_IN_GOACC_SINGLE_COPY_END, "GOACC_single_copy_end", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) -DEF_GOMP_BUILTIN (BUILT_IN_OMP_IS_INITIAL_DEVICE, "omp_is_initial_device", - BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_THREAD_NUM, "omp_get_thread_num", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads", diff --git a/gcc/tree.cc b/gcc/tree.cc index d3dfd8b1d507..2658f86cc6f3 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -8938,11 +8938,9 @@ get_file_function_name (const char *type) will be local to this file and the name is only necessary for debugging purposes. We also assign sub_I and sub_D sufixes to constructors called from - the global static constructors. These are always local. - OpenMP "declare target" offloaded constructors/destructors use "off_I" and - "off_D" for the same purpose. */ + the global static constructors. These are always local. */ else if (((type[0] == 'I' || type[0] == 'D') && targetm.have_ctors_dtors) - || ((startswith (type, "sub_") || startswith (type, "off_")) + || (startswith (type, "sub_") && (type[4] == 'I' || type[4] == 'D'))) { const char *file = main_input_filename; diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp index bf1fe1b1bdd1..d18a6471d08d 100644 --- a/libgomp/ChangeLog.omp +++ b/libgomp/ChangeLog.omp @@ -1,3 +1,15 @@ +2025-04-25 Thomas Schwinge <tschwi...@baylibre.com> + + Revert: + 2023-05-12 Julian Brown <jul...@codesourcery.com> + + * testsuite/libgomp.c++/static-aggr-constructor-destructor-1.C: New + test. + * testsuite/libgomp.c++/static-aggr-constructor-destructor-2.C: New + test. + * testsuite/libgomp.c++/static-aggr-constructor-destructor-3.C: New + test. + 2025-04-24 Tobias Burnus <tbur...@baylibre.com> Backported from master: diff --git a/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-1.C b/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-1.C deleted file mode 100644 index 91d8469a150f..000000000000 --- a/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-1.C +++ /dev/null @@ -1,28 +0,0 @@ -// { dg-do run } - -#include <cassert> - -#pragma omp declare target - -struct str { - str(int x) : _x(x) { } - int add(str o) { return _x + o._x; } - int _x; -} v1(5); - -#pragma omp end declare target - -int main() -{ - int res = -1; - str v2(2); - -#pragma omp target map(from:res) - { - res = v1.add(v2); - } - - assert (res == 7); - - return 0; -} diff --git a/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-2.C b/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-2.C deleted file mode 100644 index 1bf3ee8e31c2..000000000000 --- a/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-2.C +++ /dev/null @@ -1,31 +0,0 @@ -// { dg-do run } - -#include <cassert> - -#pragma omp declare target - -template<typename T> -struct str { - str(T x) : _x(x) { } - T add(str o) { return _x + o._x; } - T _x; -}; - -str<long> v1(5); - -#pragma omp end declare target - -int main() -{ - long res = -1; - str<long> v2(2); - -#pragma omp target map(from:res) - { - res = v1.add(v2); - } - - assert (res == 7); - - return 0; -} diff --git a/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-3.C b/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-3.C deleted file mode 100644 index 8d4aff21cd79..000000000000 --- a/libgomp/testsuite/libgomp.c++/static-aggr-constructor-destructor-3.C +++ /dev/null @@ -1,36 +0,0 @@ -// { dg-do run } - -#include <cassert> - -#pragma omp declare target - -struct item { - item(item *p, int v) : prev(p), val(v) { } - int get() { return prev ? prev->get() * val : val; } - item *prev; - int val; -}; - -/* This case demonstrates why constructing on the host and then copying to - the target would be less desirable. With on-target construction, "prev" - for each 'item' will be a device pointer, not a host pointer. */ -item hubert1(nullptr, 3); -item hubert2(&hubert1, 5); -item hubert3(&hubert2, 7); -item hubert4(&hubert3, 11); - -#pragma omp end declare target - -int main() -{ - int res = -1; - -#pragma omp target map(from:res) - { - res = hubert4.get (); - } - - assert (res == 1155); - - return 0; -}