diff options
author | Thomas Schwinge <thomas@codesourcery.com> | 2015-01-15 21:11:12 +0100 |
---|---|---|
committer | Thomas Schwinge <tschwinge@gcc.gnu.org> | 2015-01-15 21:11:12 +0100 |
commit | 41dbbb3789850dfea98dd8984f69806284f87b6e (patch) | |
tree | 97a0bb274cc7583206397ba37ab5c0bbe01cb04d /gcc | |
parent | 96a87981994da859c17259d8c4dccb6602476b0e (diff) | |
download | gcc-41dbbb3789850dfea98dd8984f69806284f87b6e.zip gcc-41dbbb3789850dfea98dd8984f69806284f87b6e.tar.gz gcc-41dbbb3789850dfea98dd8984f69806284f87b6e.tar.bz2 |
Merge current set of OpenACC changes from gomp-4_0-branch.
contrib/
* gcc_update (files_and_dependencies): Update rules for new
libgomp/plugin/Makefrag.am and libgomp/plugin/configfrag.ac files.
gcc/
* builtin-types.def (BT_FN_VOID_INT_INT_VAR)
(BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR)
(BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR):
New function types.
* builtins.c: Include "gomp-constants.h".
(expand_builtin_acc_on_device): New function.
(expand_builtin, is_inexpensive_builtin): Handle
BUILT_IN_ACC_ON_DEVICE.
* builtins.def (DEF_GOACC_BUILTIN, DEF_GOACC_BUILTIN_COMPILER):
New macros.
* cgraph.c (cgraph_node::create): Consider flag_openacc next to
flag_openmp.
* config.gcc <nvptx-*> (tm_file): Add nvptx/offload.h.
<*-intelmic-* | *-intelmicemul-*> (tm_file): Add
i386/intelmic-offload.h.
* gcc.c (LINK_COMMAND_SPEC, GOMP_SELF_SPECS): For -fopenacc, link
to libgomp and its dependencies.
* config/arc/arc.h (LINK_COMMAND_SPEC): Likewise.
* config/darwin.h (LINK_COMMAND_SPEC_A): Likewise.
* config/i386/mingw32.h (GOMP_SELF_SPECS): Likewise.
* config/ia64/hpux.h (LIB_SPEC): Likewise.
* config/pa/pa-hpux11.h (LIB_SPEC): Likewise.
* config/pa/pa64-hpux.h (LIB_SPEC): Likewise.
* doc/generic.texi: Update for OpenACC changes.
* doc/gimple.texi: Likewise.
* doc/invoke.texi: Likewise.
* doc/sourcebuild.texi: Likewise.
* gimple-pretty-print.c (dump_gimple_omp_for): Handle
GF_OMP_FOR_KIND_OACC_LOOP.
(dump_gimple_omp_target): Handle GF_OMP_TARGET_KIND_OACC_KERNELS,
GF_OMP_TARGET_KIND_OACC_PARALLEL, GF_OMP_TARGET_KIND_OACC_DATA,
GF_OMP_TARGET_KIND_OACC_UPDATE,
GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA.
Dump more data.
* gimple.c: Update comments for OpenACC changes.
* gimple.def: Likewise.
* gimple.h: Likewise.
(enum gf_mask): Add GF_OMP_FOR_KIND_OACC_LOOP,
GF_OMP_TARGET_KIND_OACC_PARALLEL, GF_OMP_TARGET_KIND_OACC_KERNELS,
GF_OMP_TARGET_KIND_OACC_DATA, GF_OMP_TARGET_KIND_OACC_UPDATE,
GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA.
(gimple_omp_for_cond, gimple_omp_for_set_cond): Sort in the
appropriate place.
(is_gimple_omp_oacc, is_gimple_omp_offloaded): New functions.
* gimplify.c: Include "gomp-constants.h".
Update comments for OpenACC changes.
(is_gimple_stmt): Handle OACC_PARALLEL, OACC_KERNELS, OACC_DATA,
OACC_HOST_DATA, OACC_DECLARE, OACC_UPDATE, OACC_ENTER_DATA,
OACC_EXIT_DATA, OACC_CACHE, OACC_LOOP.
(gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): Handle
OMP_CLAUSE__CACHE_, OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT,
OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER,
OMP_CLAUSE_VECTOR, OMP_CLAUSE_DEVICE_RESIDENT,
OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE_INDEPENDENT, OMP_CLAUSE_AUTO,
OMP_CLAUSE_SEQ.
(gimplify_adjust_omp_clauses_1, gimplify_adjust_omp_clauses): Use
GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use
OMP_CLAUSE_SET_MAP_KIND.
(gimplify_oacc_cache): New function.
(gimplify_omp_for): Handle OACC_LOOP.
(gimplify_omp_workshare): Handle OACC_KERNELS, OACC_PARALLEL,
OACC_DATA.
(gimplify_omp_target_update): Handle OACC_ENTER_DATA,
OACC_EXIT_DATA, OACC_UPDATE.
(gimplify_expr): Handle OACC_LOOP, OACC_CACHE, OACC_HOST_DATA,
OACC_DECLARE, OACC_KERNELS, OACC_PARALLEL, OACC_DATA,
OACC_ENTER_DATA, OACC_EXIT_DATA, OACC_UPDATE.
(gimplify_body): Consider flag_openacc next to flag_openmp.
* lto-streamer-out.c: Include "gomp-constants.h".
* omp-builtins.def (BUILT_IN_ACC_GET_DEVICE_TYPE)
(BUILT_IN_GOACC_DATA_START, BUILT_IN_GOACC_DATA_END)
(BUILT_IN_GOACC_ENTER_EXIT_DATA, BUILT_IN_GOACC_PARALLEL)
(BUILT_IN_GOACC_UPDATE, BUILT_IN_GOACC_WAIT)
(BUILT_IN_GOACC_GET_THREAD_NUM, BUILT_IN_GOACC_GET_NUM_THREADS)
(BUILT_IN_ACC_ON_DEVICE): New builtins.
* omp-low.c: Include "gomp-constants.h".
Update comments for OpenACC changes.
(struct omp_context): Add reduction_map, gwv_below, gwv_this
members.
(extract_omp_for_data, use_pointer_for_field, install_var_field)
(new_omp_context, delete_omp_context, scan_sharing_clauses)
(create_omp_child_function, scan_omp_for, scan_omp_target)
(check_omp_nesting_restrictions, lower_reduction_clauses)
(build_omp_regions_1, diagnose_sb_0, make_gimple_omp_edges):
Update for OpenACC changes.
(scan_sharing_clauses): Handle OMP_CLAUSE_NUM_GANGS:
OMP_CLAUSE_NUM_WORKERS: OMP_CLAUSE_VECTOR_LENGTH,
OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT, OMP_CLAUSE_GANG,
OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_DEVICE_RESIDENT,
OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE__CACHE_, OMP_CLAUSE_INDEPENDENT,
OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ. Use GOMP_MAP_* instead of
OMP_CLAUSE_MAP_*.
(expand_omp_for_static_nochunk, expand_omp_for_static_chunk):
Handle GF_OMP_FOR_KIND_OACC_LOOP.
(expand_omp_target, lower_omp_target): Handle
GF_OMP_TARGET_KIND_OACC_PARALLEL, GF_OMP_TARGET_KIND_OACC_KERNELS,
GF_OMP_TARGET_KIND_OACC_UPDATE,
GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA,
GF_OMP_TARGET_KIND_OACC_DATA.
(pass_expand_omp::execute, execute_lower_omp)
(pass_diagnose_omp_blocks::gate): Consider flag_openacc next to
flag_openmp.
(offload_symbol_decl): New variable.
(oacc_get_reduction_array_id, oacc_max_threads)
(get_offload_symbol_decl, get_base_type, lookup_oacc_reduction)
(maybe_lookup_oacc_reduction, enclosing_target_ctx)
(oacc_loop_or_target_p, oacc_lower_reduction_var_helper)
(oacc_gimple_assign, oacc_initialize_reduction_data)
(oacc_finalize_reduction_data, oacc_process_reduction_data): New
functions.
(is_targetreg_ctx): Remove function.
* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE__CACHE_,
OMP_CLAUSE_DEVICE_RESIDENT, OMP_CLAUSE_USE_DEVICE,
OMP_CLAUSE_GANG, OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT,
OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ, OMP_CLAUSE_INDEPENDENT,
OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_NUM_GANGS,
OMP_CLAUSE_NUM_WORKERS, OMP_CLAUSE_VECTOR_LENGTH.
* tree.c (omp_clause_code_name, walk_tree_1): Update accordingly.
* tree.h (OMP_CLAUSE_GANG_EXPR, OMP_CLAUSE_GANG_STATIC_EXPR)
(OMP_CLAUSE_ASYNC_EXPR, OMP_CLAUSE_WAIT_EXPR)
(OMP_CLAUSE_VECTOR_EXPR, OMP_CLAUSE_WORKER_EXPR)
(OMP_CLAUSE_NUM_GANGS_EXPR, OMP_CLAUSE_NUM_WORKERS_EXPR)
(OMP_CLAUSE_VECTOR_LENGTH_EXPR): New macros.
* tree-core.h: Update comments for OpenACC changes.
(enum omp_clause_map_kind): Remove.
(struct tree_omp_clause): Change type of map_kind member from enum
omp_clause_map_kind to unsigned char.
* tree-inline.c: Update comments for OpenACC changes.
* tree-nested.c: Likewise. Include "gomp-constants.h".
(convert_nonlocal_reference_stmt, convert_local_reference_stmt)
(convert_tramp_reference_stmt, convert_gimple_call): Update for
OpenACC changes. Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use
OMP_CLAUSE_SET_MAP_KIND.
* tree-pretty-print.c: Include "gomp-constants.h".
(dump_omp_clause): Handle OMP_CLAUSE_DEVICE_RESIDENT,
OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE__CACHE_, OMP_CLAUSE_GANG,
OMP_CLAUSE_ASYNC, OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ,
OMP_CLAUSE_WAIT, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR,
OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_INDEPENDENT. Use GOMP_MAP_*
instead of OMP_CLAUSE_MAP_*.
(dump_generic_node): Handle OACC_PARALLEL, OACC_KERNELS,
OACC_DATA, OACC_HOST_DATA, OACC_DECLARE, OACC_UPDATE,
OACC_ENTER_DATA, OACC_EXIT_DATA, OACC_CACHE, OACC_LOOP.
* tree-streamer-in.c: Include "gomp-constants.h".
(unpack_ts_omp_clause_value_fields) Use GOMP_MAP_* instead of
OMP_CLAUSE_MAP_*. Use OMP_CLAUSE_SET_MAP_KIND.
* tree-streamer-out.c: Include "gomp-constants.h".
(pack_ts_omp_clause_value_fields): Use GOMP_MAP_* instead of
OMP_CLAUSE_MAP_*.
* tree.def (OACC_PARALLEL, OACC_KERNELS, OACC_DATA)
(OACC_HOST_DATA, OACC_LOOP, OACC_CACHE, OACC_DECLARE)
(OACC_ENTER_DATA, OACC_EXIT_DATA, OACC_UPDATE): New tree codes.
* tree.c (omp_clause_num_ops): Update accordingly.
* tree.h (OMP_BODY, OMP_CLAUSES, OMP_LOOP_CHECK, OMP_CLAUSE_SIZE):
Likewise.
(OACC_PARALLEL_BODY, OACC_PARALLEL_CLAUSES, OACC_KERNELS_BODY)
(OACC_KERNELS_CLAUSES, OACC_DATA_BODY, OACC_DATA_CLAUSES)
(OACC_HOST_DATA_BODY, OACC_HOST_DATA_CLAUSES, OACC_CACHE_CLAUSES)
(OACC_DECLARE_CLAUSES, OACC_ENTER_DATA_CLAUSES)
(OACC_EXIT_DATA_CLAUSES, OACC_UPDATE_CLAUSES)
(OACC_KERNELS_COMBINED, OACC_PARALLEL_COMBINED): New macros.
* tree.h (OMP_CLAUSE_MAP_KIND): Cast it to enum gomp_map_kind.
(OMP_CLAUSE_SET_MAP_KIND): New macro.
* varpool.c (varpool_node::get_create): Consider flag_openacc next
to flag_openmp.
* config/i386/intelmic-offload.h: New file.
* config/nvptx/offload.h: Likewise.
gcc/ada/
* gcc-interface/utils.c (DEF_FUNCTION_TYPE_VAR_8)
(DEF_FUNCTION_TYPE_VAR_12): New macros.
gcc/c-family/
* c.opt (fopenacc): New option.
* c-cppbuiltin.c (c_cpp_builtins): Conditionally define _OPENACC.
* c-common.c (DEF_FUNCTION_TYPE_VAR_8, DEF_FUNCTION_TYPE_VAR_12):
New macros.
* c-common.h (c_finish_oacc_wait): New prototype.
* c-omp.c: Include "omp-low.h" and "gomp-constants.h".
(c_finish_oacc_wait): New function.
* c-pragma.c (oacc_pragmas): New variable.
(c_pp_lookup_pragma, init_pragma): Handle it.
* c-pragma.h (enum pragma_kind): Add PRAGMA_OACC_CACHE,
PRAGMA_OACC_DATA, PRAGMA_OACC_ENTER_DATA, PRAGMA_OACC_EXIT_DATA,
PRAGMA_OACC_KERNELS, PRAGMA_OACC_LOOP, PRAGMA_OACC_PARALLEL,
PRAGMA_OACC_UPDATE, PRAGMA_OACC_WAIT.
(enum pragma_omp_clause): Add PRAGMA_OACC_CLAUSE_ASYNC,
PRAGMA_OACC_CLAUSE_AUTO, PRAGMA_OACC_CLAUSE_COLLAPSE,
PRAGMA_OACC_CLAUSE_COPY, PRAGMA_OACC_CLAUSE_COPYIN,
PRAGMA_OACC_CLAUSE_COPYOUT, PRAGMA_OACC_CLAUSE_CREATE,
PRAGMA_OACC_CLAUSE_DELETE, PRAGMA_OACC_CLAUSE_DEVICE,
PRAGMA_OACC_CLAUSE_DEVICEPTR, PRAGMA_OACC_CLAUSE_FIRSTPRIVATE,
PRAGMA_OACC_CLAUSE_GANG, PRAGMA_OACC_CLAUSE_HOST,
PRAGMA_OACC_CLAUSE_IF, PRAGMA_OACC_CLAUSE_NUM_GANGS,
PRAGMA_OACC_CLAUSE_NUM_WORKERS, PRAGMA_OACC_CLAUSE_PRESENT,
PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY,
PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN,
PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT,
PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE, PRAGMA_OACC_CLAUSE_PRIVATE,
PRAGMA_OACC_CLAUSE_REDUCTION, PRAGMA_OACC_CLAUSE_SELF,
PRAGMA_OACC_CLAUSE_SEQ, PRAGMA_OACC_CLAUSE_VECTOR,
PRAGMA_OACC_CLAUSE_VECTOR_LENGTH, PRAGMA_OACC_CLAUSE_WAIT,
PRAGMA_OACC_CLAUSE_WORKER.
gcc/c/
* c-parser.c: Include "gomp-constants.h".
(c_parser_omp_clause_map): Use enum gomp_map_kind instead of enum
omp_clause_map_kind. Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*.
Use OMP_CLAUSE_SET_MAP_KIND.
(c_parser_pragma): Handle PRAGMA_OACC_ENTER_DATA,
PRAGMA_OACC_EXIT_DATA, PRAGMA_OACC_UPDATE.
(c_parser_omp_construct): Handle PRAGMA_OACC_CACHE,
PRAGMA_OACC_DATA, PRAGMA_OACC_KERNELS, PRAGMA_OACC_LOOP,
PRAGMA_OACC_PARALLEL, PRAGMA_OACC_WAIT.
(c_parser_omp_clause_name): Handle "auto", "async", "copy",
"copyout", "create", "delete", "deviceptr", "gang", "host",
"num_gangs", "num_workers", "present", "present_or_copy", "pcopy",
"present_or_copyin", "pcopyin", "present_or_copyout", "pcopyout",
"present_or_create", "pcreate", "seq", "self", "vector",
"vector_length", "wait", "worker".
(OACC_DATA_CLAUSE_MASK, OACC_KERNELS_CLAUSE_MASK)
(OACC_ENTER_DATA_CLAUSE_MASK, OACC_EXIT_DATA_CLAUSE_MASK)
(OACC_LOOP_CLAUSE_MASK, OACC_PARALLEL_CLAUSE_MASK)
(OACC_UPDATE_CLAUSE_MASK, OACC_WAIT_CLAUSE_MASK): New macros.
(c_parser_omp_variable_list): Handle OMP_CLAUSE__CACHE_.
(c_parser_oacc_wait_list, c_parser_oacc_data_clause)
(c_parser_oacc_data_clause_deviceptr)
(c_parser_omp_clause_num_gangs, c_parser_omp_clause_num_workers)
(c_parser_oacc_clause_async, c_parser_oacc_clause_wait)
(c_parser_omp_clause_vector_length, c_parser_oacc_all_clauses)
(c_parser_oacc_cache, c_parser_oacc_data, c_parser_oacc_kernels)
(c_parser_oacc_enter_exit_data, c_parser_oacc_loop)
(c_parser_oacc_parallel, c_parser_oacc_update)
(c_parser_oacc_wait): New functions.
* c-tree.h (c_finish_oacc_parallel, c_finish_oacc_kernels)
(c_finish_oacc_data): New prototypes.
* c-typeck.c: Include "gomp-constants.h".
(handle_omp_array_sections): Handle GOMP_MAP_FORCE_DEVICEPTR. Use
GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use
OMP_CLAUSE_SET_MAP_KIND.
(c_finish_oacc_parallel, c_finish_oacc_kernels)
(c_finish_oacc_data): New functions.
(c_finish_omp_clauses): Handle OMP_CLAUSE__CACHE_,
OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS,
OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT,
OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ, OMP_CLAUSE_GANG,
OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, and OMP_CLAUSE_MAP's
GOMP_MAP_FORCE_DEVICEPTR.
gcc/cp/
* parser.c: Include "gomp-constants.h".
(cp_parser_omp_clause_map): Use enum gomp_map_kind instead of enum
omp_clause_map_kind. Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*.
Use OMP_CLAUSE_SET_MAP_KIND.
(cp_parser_omp_construct, cp_parser_pragma): Handle
PRAGMA_OACC_CACHE, PRAGMA_OACC_DATA, PRAGMA_OACC_ENTER_DATA,
PRAGMA_OACC_EXIT_DATA, PRAGMA_OACC_KERNELS, PRAGMA_OACC_PARALLEL,
PRAGMA_OACC_LOOP, PRAGMA_OACC_UPDATE, PRAGMA_OACC_WAIT.
(cp_parser_omp_clause_name): Handle "async", "copy", "copyout",
"create", "delete", "deviceptr", "host", "num_gangs",
"num_workers", "present", "present_or_copy", "pcopy",
"present_or_copyin", "pcopyin", "present_or_copyout", "pcopyout",
"present_or_create", "pcreate", "vector_length", "wait".
(OACC_DATA_CLAUSE_MASK, OACC_ENTER_DATA_CLAUSE_MASK)
(OACC_EXIT_DATA_CLAUSE_MASK, OACC_KERNELS_CLAUSE_MASK)
(OACC_LOOP_CLAUSE_MASK, OACC_PARALLEL_CLAUSE_MASK)
(OACC_UPDATE_CLAUSE_MASK, OACC_WAIT_CLAUSE_MASK): New macros.
(cp_parser_omp_var_list_no_open): Handle OMP_CLAUSE__CACHE_.
(cp_parser_oacc_data_clause, cp_parser_oacc_data_clause_deviceptr)
(cp_parser_oacc_clause_vector_length, cp_parser_oacc_wait_list)
(cp_parser_oacc_clause_wait, cp_parser_omp_clause_num_gangs)
(cp_parser_omp_clause_num_workers, cp_parser_oacc_clause_async)
(cp_parser_oacc_all_clauses, cp_parser_oacc_cache)
(cp_parser_oacc_data, cp_parser_oacc_enter_exit_data)
(cp_parser_oacc_kernels, cp_parser_oacc_loop)
(cp_parser_oacc_parallel, cp_parser_oacc_update)
(cp_parser_oacc_wait): New functions.
* cp-tree.h (finish_oacc_data, finish_oacc_kernels)
(finish_oacc_parallel): New prototypes.
* semantics.c: Include "gomp-constants.h".
(handle_omp_array_sections): Handle GOMP_MAP_FORCE_DEVICEPTR. Use
GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use
OMP_CLAUSE_SET_MAP_KIND.
(finish_omp_clauses): Handle OMP_CLAUSE_ASYNC,
OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_WAIT, OMP_CLAUSE__CACHE_.
Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*.
(finish_oacc_data, finish_oacc_kernels, finish_oacc_parallel): New
functions.
gcc/fortran/
* lang.opt (fopenacc): New option.
* cpp.c (cpp_define_builtins): Conditionally define _OPENACC.
* dump-parse-tree.c (show_omp_node): Split part of it into...
(show_omp_clauses): ... this new function.
(show_omp_node, show_code_node): Handle EXEC_OACC_PARALLEL_LOOP,
EXEC_OACC_PARALLEL, EXEC_OACC_KERNELS_LOOP, EXEC_OACC_KERNELS,
EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP,
EXEC_OACC_UPDATE, EXEC_OACC_WAIT, EXEC_OACC_CACHE,
EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_DATA.
(show_namespace): Update for OpenACC.
* f95-lang.c (DEF_FUNCTION_TYPE_VAR_2, DEF_FUNCTION_TYPE_VAR_8)
(DEF_FUNCTION_TYPE_VAR_12, DEF_GOACC_BUILTIN)
(DEF_GOACC_BUILTIN_COMPILER): New macros.
* types.def (BT_FN_VOID_INT_INT_VAR)
(BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR)
(BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR):
New function types.
* gfortran.h (gfc_statement): Add ST_OACC_PARALLEL_LOOP,
ST_OACC_END_PARALLEL_LOOP, ST_OACC_PARALLEL, ST_OACC_END_PARALLEL,
ST_OACC_KERNELS, ST_OACC_END_KERNELS, ST_OACC_DATA,
ST_OACC_END_DATA, ST_OACC_HOST_DATA, ST_OACC_END_HOST_DATA,
ST_OACC_LOOP, ST_OACC_END_LOOP, ST_OACC_DECLARE, ST_OACC_UPDATE,
ST_OACC_WAIT, ST_OACC_CACHE, ST_OACC_KERNELS_LOOP,
ST_OACC_END_KERNELS_LOOP, ST_OACC_ENTER_DATA, ST_OACC_EXIT_DATA,
ST_OACC_ROUTINE.
(struct gfc_expr_list): New data type.
(gfc_get_expr_list): New macro.
(gfc_omp_map_op): Add OMP_MAP_FORCE_ALLOC, OMP_MAP_FORCE_DEALLOC,
OMP_MAP_FORCE_TO, OMP_MAP_FORCE_FROM, OMP_MAP_FORCE_TOFROM,
OMP_MAP_FORCE_PRESENT, OMP_MAP_FORCE_DEVICEPTR.
(OMP_LIST_FIRST, OMP_LIST_DEVICE_RESIDENT, OMP_LIST_USE_DEVICE)
(OMP_LIST_CACHE): New enumerators.
(struct gfc_omp_clauses): Add async_expr, gang_expr, worker_expr,
vector_expr, num_gangs_expr, num_workers_expr, vector_length_expr,
wait_list, tile_list, async, gang, worker, vector, seq,
independent, wait, par_auto, gang_static, and loc members.
(struct gfc_namespace): Add oacc_declare_clauses member.
(gfc_exec_op): Add EXEC_OACC_KERNELS_LOOP,
EXEC_OACC_PARALLEL_LOOP, EXEC_OACC_PARALLEL, EXEC_OACC_KERNELS,
EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP,
EXEC_OACC_UPDATE, EXEC_OACC_WAIT, EXEC_OACC_CACHE,
EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_DATA.
(gfc_free_expr_list, gfc_resolve_oacc_directive)
(gfc_resolve_oacc_declare, gfc_resolve_oacc_parallel_loop_blocks)
(gfc_resolve_oacc_blocks): New prototypes.
* match.c (match_exit_cycle): Handle EXEC_OACC_LOOP and
EXEC_OACC_PARALLEL_LOOP.
* match.h (gfc_match_oacc_cache, gfc_match_oacc_wait)
(gfc_match_oacc_update, gfc_match_oacc_declare)
(gfc_match_oacc_loop, gfc_match_oacc_host_data)
(gfc_match_oacc_data, gfc_match_oacc_kernels)
(gfc_match_oacc_kernels_loop, gfc_match_oacc_parallel)
(gfc_match_oacc_parallel_loop, gfc_match_oacc_enter_data)
(gfc_match_oacc_exit_data, gfc_match_oacc_routine): New
prototypes.
* openmp.c: Include "diagnostic.h" and "gomp-constants.h".
(gfc_free_omp_clauses): Update for members added to struct
gfc_omp_clauses.
(gfc_match_omp_clauses): Change mask paramter to uint64_t. Add
openacc parameter.
(resolve_omp_clauses): Add openacc parameter. Update for OpenACC.
(struct fortran_omp_context): Add is_openmp member.
(gfc_resolve_omp_parallel_blocks): Initialize it.
(gfc_resolve_do_iterator): Update for OpenACC.
(gfc_resolve_omp_directive): Call
resolve_omp_directive_inside_oacc_region.
(OMP_CLAUSE_PRIVATE, OMP_CLAUSE_FIRSTPRIVATE)
(OMP_CLAUSE_LASTPRIVATE, OMP_CLAUSE_COPYPRIVATE)
(OMP_CLAUSE_SHARED, OMP_CLAUSE_COPYIN, OMP_CLAUSE_REDUCTION)
(OMP_CLAUSE_IF, OMP_CLAUSE_NUM_THREADS, OMP_CLAUSE_SCHEDULE)
(OMP_CLAUSE_DEFAULT, OMP_CLAUSE_ORDERED, OMP_CLAUSE_COLLAPSE)
(OMP_CLAUSE_UNTIED, OMP_CLAUSE_FINAL, OMP_CLAUSE_MERGEABLE)
(OMP_CLAUSE_ALIGNED, OMP_CLAUSE_DEPEND, OMP_CLAUSE_INBRANCH)
(OMP_CLAUSE_LINEAR, OMP_CLAUSE_NOTINBRANCH, OMP_CLAUSE_PROC_BIND)
(OMP_CLAUSE_SAFELEN, OMP_CLAUSE_SIMDLEN, OMP_CLAUSE_UNIFORM)
(OMP_CLAUSE_DEVICE, OMP_CLAUSE_MAP, OMP_CLAUSE_TO)
(OMP_CLAUSE_FROM, OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_THREAD_LIMIT)
(OMP_CLAUSE_DIST_SCHEDULE): Use uint64_t.
(OMP_CLAUSE_ASYNC, OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS)
(OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_COPY, OMP_CLAUSE_COPYOUT)
(OMP_CLAUSE_CREATE, OMP_CLAUSE_PRESENT)
(OMP_CLAUSE_PRESENT_OR_COPY, OMP_CLAUSE_PRESENT_OR_COPYIN)
(OMP_CLAUSE_PRESENT_OR_COPYOUT, OMP_CLAUSE_PRESENT_OR_CREATE)
(OMP_CLAUSE_DEVICEPTR, OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER)
(OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ, OMP_CLAUSE_INDEPENDENT)
(OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE_DEVICE_RESIDENT)
(OMP_CLAUSE_HOST_SELF, OMP_CLAUSE_OACC_DEVICE, OMP_CLAUSE_WAIT)
(OMP_CLAUSE_DELETE, OMP_CLAUSE_AUTO, OMP_CLAUSE_TILE): New macros.
(gfc_match_omp_clauses): Handle those.
(OACC_PARALLEL_CLAUSES, OACC_KERNELS_CLAUSES, OACC_DATA_CLAUSES)
(OACC_LOOP_CLAUSES, OACC_PARALLEL_LOOP_CLAUSES)
(OACC_KERNELS_LOOP_CLAUSES, OACC_HOST_DATA_CLAUSES)
(OACC_DECLARE_CLAUSES, OACC_UPDATE_CLAUSES)
(OACC_ENTER_DATA_CLAUSES, OACC_EXIT_DATA_CLAUSES)
(OACC_WAIT_CLAUSES): New macros.
(gfc_free_expr_list, match_oacc_expr_list, match_oacc_clause_gang)
(gfc_match_omp_map_clause, gfc_match_oacc_parallel_loop)
(gfc_match_oacc_parallel, gfc_match_oacc_kernels_loop)
(gfc_match_oacc_kernels, gfc_match_oacc_data)
(gfc_match_oacc_host_data, gfc_match_oacc_loop)
(gfc_match_oacc_declare, gfc_match_oacc_update)
(gfc_match_oacc_enter_data, gfc_match_oacc_exit_data)
(gfc_match_oacc_wait, gfc_match_oacc_cache)
(gfc_match_oacc_routine, oacc_is_loop)
(resolve_oacc_scalar_int_expr, resolve_oacc_positive_int_expr)
(check_symbol_not_pointer, check_array_not_assumed)
(resolve_oacc_data_clauses, resolve_oacc_deviceptr_clause)
(oacc_compatible_clauses, oacc_is_parallel, oacc_is_kernels)
(omp_code_to_statement, oacc_code_to_statement)
(resolve_oacc_directive_inside_omp_region)
(resolve_omp_directive_inside_oacc_region)
(resolve_oacc_nested_loops, resolve_oacc_params_in_parallel)
(resolve_oacc_loop_blocks, gfc_resolve_oacc_blocks)
(resolve_oacc_loop, resolve_oacc_cache, gfc_resolve_oacc_declare)
(gfc_resolve_oacc_directive): New functions.
* parse.c (next_free): Update for OpenACC. Move some code into...
(verify_token_free): ... this new function.
(next_fixed): Update for OpenACC. Move some code into...
(verify_token_fixed): ... this new function.
(case_executable): Add ST_OACC_UPDATE, ST_OACC_WAIT,
ST_OACC_CACHE, ST_OACC_ENTER_DATA, and ST_OACC_EXIT_DATA.
(case_exec_markers): Add ST_OACC_PARALLEL_LOOP, ST_OACC_PARALLEL,
ST_OACC_KERNELS, ST_OACC_DATA, ST_OACC_HOST_DATA, ST_OACC_LOOP,
ST_OACC_KERNELS_LOOP.
(case_decl): Add ST_OACC_ROUTINE.
(push_state, parse_critical_block, parse_progunit): Update for
OpenACC.
(gfc_ascii_statement): Handle ST_OACC_PARALLEL_LOOP,
ST_OACC_END_PARALLEL_LOOP, ST_OACC_PARALLEL, ST_OACC_END_PARALLEL,
ST_OACC_KERNELS, ST_OACC_END_KERNELS, ST_OACC_KERNELS_LOOP,
ST_OACC_END_KERNELS_LOOP, ST_OACC_DATA, ST_OACC_END_DATA,
ST_OACC_HOST_DATA, ST_OACC_END_HOST_DATA, ST_OACC_LOOP,
ST_OACC_END_LOOP, ST_OACC_DECLARE, ST_OACC_UPDATE, ST_OACC_WAIT,
ST_OACC_CACHE, ST_OACC_ENTER_DATA, ST_OACC_EXIT_DATA,
ST_OACC_ROUTINE.
(verify_st_order, parse_spec): Handle ST_OACC_DECLARE.
(parse_executable): Handle ST_OACC_PARALLEL_LOOP,
ST_OACC_KERNELS_LOOP, ST_OACC_LOOP, ST_OACC_PARALLEL,
ST_OACC_KERNELS, ST_OACC_DATA, ST_OACC_HOST_DATA.
(decode_oacc_directive, parse_oacc_structured_block)
(parse_oacc_loop, is_oacc): New functions.
* parse.h (struct gfc_state_data): Add oacc_declare_clauses
member.
(is_oacc): New prototype.
* resolve.c (gfc_resolve_blocks, gfc_resolve_code): Handle
EXEC_OACC_PARALLEL_LOOP, EXEC_OACC_PARALLEL,
EXEC_OACC_KERNELS_LOOP, EXEC_OACC_KERNELS, EXEC_OACC_DATA,
EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP, EXEC_OACC_UPDATE,
EXEC_OACC_WAIT, EXEC_OACC_CACHE, EXEC_OACC_ENTER_DATA,
EXEC_OACC_EXIT_DATA.
(resolve_codes): Call gfc_resolve_oacc_declare.
* scanner.c (openacc_flag, openacc_locus): New variables.
(skip_free_comments): Update for OpenACC. Move some code into...
(skip_omp_attribute): ... this new function.
(skip_oacc_attribute): New function.
(skip_fixed_comments, gfc_next_char_literal): Update for OpenACC.
* st.c (gfc_free_statement): Handle EXEC_OACC_PARALLEL_LOOP,
EXEC_OACC_PARALLEL, EXEC_OACC_KERNELS_LOOP, EXEC_OACC_KERNELS,
EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP,
EXEC_OACC_UPDATE, EXEC_OACC_WAIT, EXEC_OACC_CACHE,
EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_DATA.
* trans-decl.c (gfc_generate_function_code): Update for OpenACC.
* trans-openmp.c: Include "gomp-constants.h".
(gfc_omp_finish_clause, gfc_trans_omp_clauses): Use GOMP_MAP_*
instead of OMP_CLAUSE_MAP_*. Use OMP_CLAUSE_SET_MAP_KIND.
(gfc_trans_omp_clauses): Handle OMP_LIST_USE_DEVICE,
OMP_LIST_DEVICE_RESIDENT, OMP_LIST_CACHE, and OMP_MAP_FORCE_ALLOC,
OMP_MAP_FORCE_DEALLOC, OMP_MAP_FORCE_TO, OMP_MAP_FORCE_FROM,
OMP_MAP_FORCE_TOFROM, OMP_MAP_FORCE_PRESENT,
OMP_MAP_FORCE_DEVICEPTR, and gfc_omp_clauses' async, seq,
independent, wait_list, num_gangs_expr, num_workers_expr,
vector_length_expr, vector, vector_expr, worker, worker_expr,
gang, gang_expr members.
(gfc_trans_omp_do): Handle EXEC_OACC_LOOP.
(gfc_convert_expr_to_tree, gfc_trans_oacc_construct)
(gfc_trans_oacc_executable_directive)
(gfc_trans_oacc_wait_directive, gfc_trans_oacc_combined_directive)
(gfc_trans_oacc_declare, gfc_trans_oacc_directive): New functions.
* trans-stmt.c (gfc_trans_block_construct): Update for OpenACC.
* trans-stmt.h (gfc_trans_oacc_directive, gfc_trans_oacc_declare):
New prototypes.
* trans.c (tranc_code): Handle EXEC_OACC_CACHE, EXEC_OACC_WAIT,
EXEC_OACC_UPDATE, EXEC_OACC_LOOP, EXEC_OACC_HOST_DATA,
EXEC_OACC_DATA, EXEC_OACC_KERNELS, EXEC_OACC_KERNELS_LOOP,
EXEC_OACC_PARALLEL, EXEC_OACC_PARALLEL_LOOP, EXEC_OACC_ENTER_DATA,
EXEC_OACC_EXIT_DATA.
* gfortran.texi: Update for OpenACC.
* intrinsic.texi: Likewise.
* invoke.texi: Likewise.
gcc/lto/
* lto-lang.c (DEF_FUNCTION_TYPE_VAR_8, DEF_FUNCTION_TYPE_VAR_12):
New macros.
* lto.c: Include "gomp-constants.h".
gcc/testsuite/
* lib/target-supports.exp (check_effective_target_fopenacc): New
procedure.
* g++.dg/goacc-gomp/goacc-gomp.exp: New file.
* g++.dg/goacc/goacc.exp: Likewise.
* gcc.dg/goacc-gomp/goacc-gomp.exp: Likewise.
* gcc.dg/goacc/goacc.exp: Likewise.
* gfortran.dg/goacc/goacc.exp: Likewise.
* c-c++-common/cpp/openacc-define-1.c: New file.
* c-c++-common/cpp/openacc-define-2.c: Likewise.
* c-c++-common/cpp/openacc-define-3.c: Likewise.
* c-c++-common/goacc-gomp/nesting-1.c: Likewise.
* c-c++-common/goacc-gomp/nesting-fail-1.c: Likewise.
* c-c++-common/goacc/acc_on_device-2-off.c: Likewise.
* c-c++-common/goacc/acc_on_device-2.c: Likewise.
* c-c++-common/goacc/asyncwait-1.c: Likewise.
* c-c++-common/goacc/cache-1.c: Likewise.
* c-c++-common/goacc/clauses-fail.c: Likewise.
* c-c++-common/goacc/collapse-1.c: Likewise.
* c-c++-common/goacc/data-1.c: Likewise.
* c-c++-common/goacc/data-2.c: Likewise.
* c-c++-common/goacc/data-clause-duplicate-1.c: Likewise.
* c-c++-common/goacc/deviceptr-1.c: Likewise.
* c-c++-common/goacc/deviceptr-2.c: Likewise.
* c-c++-common/goacc/deviceptr-3.c: Likewise.
* c-c++-common/goacc/if-clause-1.c: Likewise.
* c-c++-common/goacc/if-clause-2.c: Likewise.
* c-c++-common/goacc/kernels-1.c: Likewise.
* c-c++-common/goacc/loop-1.c: Likewise.
* c-c++-common/goacc/loop-private-1.c: Likewise.
* c-c++-common/goacc/nesting-1.c: Likewise.
* c-c++-common/goacc/nesting-data-1.c: Likewise.
* c-c++-common/goacc/nesting-fail-1.c: Likewise.
* c-c++-common/goacc/parallel-1.c: Likewise.
* c-c++-common/goacc/pcopy.c: Likewise.
* c-c++-common/goacc/pcopyin.c: Likewise.
* c-c++-common/goacc/pcopyout.c: Likewise.
* c-c++-common/goacc/pcreate.c: Likewise.
* c-c++-common/goacc/pragma_context.c: Likewise.
* c-c++-common/goacc/present-1.c: Likewise.
* c-c++-common/goacc/reduction-1.c: Likewise.
* c-c++-common/goacc/reduction-2.c: Likewise.
* c-c++-common/goacc/reduction-3.c: Likewise.
* c-c++-common/goacc/reduction-4.c: Likewise.
* c-c++-common/goacc/sb-1.c: Likewise.
* c-c++-common/goacc/sb-2.c: Likewise.
* c-c++-common/goacc/sb-3.c: Likewise.
* c-c++-common/goacc/update-1.c: Likewise.
* gcc.dg/goacc/acc_on_device-1.c: Likewise.
* gfortran.dg/goacc/acc_on_device-1.f95: Likewise.
* gfortran.dg/goacc/acc_on_device-2-off.f95: Likewise.
* gfortran.dg/goacc/acc_on_device-2.f95: Likewise.
* gfortran.dg/goacc/assumed.f95: Likewise.
* gfortran.dg/goacc/asyncwait-1.f95: Likewise.
* gfortran.dg/goacc/asyncwait-2.f95: Likewise.
* gfortran.dg/goacc/asyncwait-3.f95: Likewise.
* gfortran.dg/goacc/asyncwait-4.f95: Likewise.
* gfortran.dg/goacc/branch.f95: Likewise.
* gfortran.dg/goacc/cache-1.f95: Likewise.
* gfortran.dg/goacc/coarray.f95: Likewise.
* gfortran.dg/goacc/continuation-free-form.f95: Likewise.
* gfortran.dg/goacc/cray.f95: Likewise.
* gfortran.dg/goacc/critical.f95: Likewise.
* gfortran.dg/goacc/data-clauses.f95: Likewise.
* gfortran.dg/goacc/data-tree.f95: Likewise.
* gfortran.dg/goacc/declare-1.f95: Likewise.
* gfortran.dg/goacc/enter-exit-data.f95: Likewise.
* gfortran.dg/goacc/fixed-1.f: Likewise.
* gfortran.dg/goacc/fixed-2.f: Likewise.
* gfortran.dg/goacc/fixed-3.f: Likewise.
* gfortran.dg/goacc/fixed-4.f: Likewise.
* gfortran.dg/goacc/host_data-tree.f95: Likewise.
* gfortran.dg/goacc/if.f95: Likewise.
* gfortran.dg/goacc/kernels-tree.f95: Likewise.
* gfortran.dg/goacc/list.f95: Likewise.
* gfortran.dg/goacc/literal.f95: Likewise.
* gfortran.dg/goacc/loop-1.f95: Likewise.
* gfortran.dg/goacc/loop-2.f95: Likewise.
* gfortran.dg/goacc/loop-3.f95: Likewise.
* gfortran.dg/goacc/loop-tree-1.f90: Likewise.
* gfortran.dg/goacc/omp.f95: Likewise.
* gfortran.dg/goacc/parallel-kernels-clauses.f95: Likewise.
* gfortran.dg/goacc/parallel-kernels-regions.f95: Likewise.
* gfortran.dg/goacc/parallel-tree.f95: Likewise.
* gfortran.dg/goacc/parameter.f95: Likewise.
* gfortran.dg/goacc/private-1.f95: Likewise.
* gfortran.dg/goacc/private-2.f95: Likewise.
* gfortran.dg/goacc/private-3.f95: Likewise.
* gfortran.dg/goacc/pure-elemental-procedures.f95: Likewise.
* gfortran.dg/goacc/reduction-2.f95: Likewise.
* gfortran.dg/goacc/reduction.f95: Likewise.
* gfortran.dg/goacc/routine-1.f90: Likewise.
* gfortran.dg/goacc/routine-2.f90: Likewise.
* gfortran.dg/goacc/sentinel-free-form.f95: Likewise.
* gfortran.dg/goacc/several-directives.f95: Likewise.
* gfortran.dg/goacc/sie.f95: Likewise.
* gfortran.dg/goacc/subarrays.f95: Likewise.
* gfortran.dg/gomp/map-1.f90: Likewise.
* gfortran.dg/openacc-define-1.f90: Likewise.
* gfortran.dg/openacc-define-2.f90: Likewise.
* gfortran.dg/openacc-define-3.f90: Likewise.
* g++.dg/gomp/block-1.C: Update for changed compiler output.
* g++.dg/gomp/block-2.C: Likewise.
* g++.dg/gomp/block-3.C: Likewise.
* g++.dg/gomp/block-5.C: Likewise.
* g++.dg/gomp/target-1.C: Likewise.
* g++.dg/gomp/target-2.C: Likewise.
* g++.dg/gomp/taskgroup-1.C: Likewise.
* g++.dg/gomp/teams-1.C: Likewise.
* gcc.dg/cilk-plus/jump-openmp.c: Likewise.
* gcc.dg/cilk-plus/jump.c: Likewise.
* gcc.dg/gomp/block-1.c: Likewise.
* gcc.dg/gomp/block-10.c: Likewise.
* gcc.dg/gomp/block-2.c: Likewise.
* gcc.dg/gomp/block-3.c: Likewise.
* gcc.dg/gomp/block-4.c: Likewise.
* gcc.dg/gomp/block-5.c: Likewise.
* gcc.dg/gomp/block-6.c: Likewise.
* gcc.dg/gomp/block-7.c: Likewise.
* gcc.dg/gomp/block-8.c: Likewise.
* gcc.dg/gomp/block-9.c: Likewise.
* gcc.dg/gomp/target-1.c: Likewise.
* gcc.dg/gomp/target-2.c: Likewise.
* gcc.dg/gomp/taskgroup-1.c: Likewise.
* gcc.dg/gomp/teams-1.c: Likewise.
include/
* gomp-constants.h: New file.
libgomp/
* Makefile.am (search_path): Add $(top_srcdir)/../include.
(libgomp_la_SOURCES): Add splay-tree.c, libgomp-plugin.c,
oacc-parallel.c, oacc-host.c, oacc-init.c, oacc-mem.c,
oacc-async.c, oacc-plugin.c, oacc-cuda.c.
[USE_FORTRAN] (libgomp_la_SOURCES): Add openacc.f90.
Include $(top_srcdir)/plugin/Makefrag.am.
(nodist_libsubinclude_HEADERS): Add openacc.h.
[USE_FORTRAN] (nodist_finclude_HEADERS): Add openacc_lib.h,
openacc.f90, openacc.mod, openacc_kinds.mod.
(omp_lib.mod): Generalize into...
(%.mod): ... this new rule.
(openacc_kinds.mod, openacc.mod): New rules.
* plugin/configfrag.ac: New file.
* configure.ac: Move plugin/offloading support into it. Include
it. Instantiate testsuite/libgomp-test-support.pt.exp.
* plugin/Makefrag.am: New file.
* testsuite/Makefile.am (OFFLOAD_TARGETS)
(OFFLOAD_ADDITIONAL_OPTIONS, OFFLOAD_ADDITIONAL_LIB_PATHS): Don't
export.
(libgomp-test-support.exp): New rule.
(all-local): Depend on it.
* Makefile.in: Regenerate.
* testsuite/Makefile.in: Regenerate.
* config.h.in: Likewise.
* configure: Likewise.
* configure.tgt: Harden shell syntax.
* env.c: Include "oacc-int.h".
(parse_acc_device_type): New function.
(gomp_debug_var, goacc_device_type, goacc_device_num): New
variables.
(initialize_env): Initialize those. Call
goacc_runtime_initialize.
* error.c (gomp_vdebug, gomp_debug, gomp_vfatal): New functions.
(gomp_fatal): Call gomp_vfatal.
* libgomp.h: Include "libgomp-plugin.h" and <stdarg.h>.
(gomp_debug_var, goacc_device_type, goacc_device_num, gomp_vdebug)
(gomp_debug, gomp_verror, gomp_vfatal, gomp_init_targets_once)
(splay_tree_node, splay_tree, splay_tree_key)
(struct target_mem_desc, struct splay_tree_key_s)
(struct gomp_memory_mapping, struct acc_dispatch_t)
(struct gomp_device_descr, gomp_acc_insert_pointer)
(gomp_acc_remove_pointer, target_mem_desc, gomp_copy_from_async)
(gomp_unmap_vars, gomp_init_device, gomp_init_tables)
(gomp_free_memmap, gomp_fini_device): New declarations.
(gomp_vdebug, gomp_debug): New macros.
Include "splay-tree.h".
* libgomp.map (OACC_2.0): New symbol version. Use for
acc_get_num_devices, acc_get_num_devices_h_, acc_set_device_type,
acc_set_device_type_h_, acc_get_device_type,
acc_get_device_type_h_, acc_set_device_num, acc_set_device_num_h_,
acc_get_device_num, acc_get_device_num_h_, acc_async_test,
acc_async_test_h_, acc_async_test_all, acc_async_test_all_h_,
acc_wait, acc_wait_h_, acc_wait_async, acc_wait_async_h_,
acc_wait_all, acc_wait_all_h_, acc_wait_all_async,
acc_wait_all_async_h_, acc_init, acc_init_h_, acc_shutdown,
acc_shutdown_h_, acc_on_device, acc_on_device_h_, acc_malloc,
acc_free, acc_copyin, acc_copyin_32_h_, acc_copyin_64_h_,
acc_copyin_array_h_, acc_present_or_copyin,
acc_present_or_copyin_32_h_, acc_present_or_copyin_64_h_,
acc_present_or_copyin_array_h_, acc_create, acc_create_32_h_,
acc_create_64_h_, acc_create_array_h_, acc_present_or_create,
acc_present_or_create_32_h_, acc_present_or_create_64_h_,
acc_present_or_create_array_h_, acc_copyout, acc_copyout_32_h_,
acc_copyout_64_h_, acc_copyout_array_h_, acc_delete,
acc_delete_32_h_, acc_delete_64_h_, acc_delete_array_h_,
acc_update_device, acc_update_device_32_h_,
acc_update_device_64_h_, acc_update_device_array_h_,
acc_update_self, acc_update_self_32_h_, acc_update_self_64_h_,
acc_update_self_array_h_, acc_map_data, acc_unmap_data,
acc_deviceptr, acc_hostptr, acc_is_present, acc_is_present_32_h_,
acc_is_present_64_h_, acc_is_present_array_h_,
acc_memcpy_to_device, acc_memcpy_from_device,
acc_get_current_cuda_device, acc_get_current_cuda_context,
acc_get_cuda_stream, acc_set_cuda_stream.
(GOACC_2.0): New symbol version. Use for GOACC_data_end,
GOACC_data_start, GOACC_enter_exit_data, GOACC_parallel,
GOACC_update, GOACC_wait, GOACC_get_thread_num,
GOACC_get_num_threads.
(GOMP_PLUGIN_1.0): New symbol version. Use for
GOMP_PLUGIN_malloc, GOMP_PLUGIN_malloc_cleared,
GOMP_PLUGIN_realloc, GOMP_PLUGIN_debug, GOMP_PLUGIN_error,
GOMP_PLUGIN_fatal, GOMP_PLUGIN_async_unmap_vars,
GOMP_PLUGIN_acc_thread.
* libgomp.texi: Update for OpenACC changes, and GOMP_DEBUG
environment variable.
* libgomp_g.h (GOACC_data_start, GOACC_data_end)
(GOACC_enter_exit_data, GOACC_parallel, GOACC_update, GOACC_wait)
(GOACC_get_num_threads, GOACC_get_thread_num): New declarations.
* splay-tree.h (splay_tree_lookup, splay_tree_insert)
(splay_tree_remove): New declarations.
(rotate_left, rotate_right, splay_tree_splay, splay_tree_insert)
(splay_tree_remove, splay_tree_lookup): Move into...
* splay-tree.c: ... this new file.
* target.c: Include "oacc-plugin.h", "oacc-int.h", <assert.h>.
(splay_tree_node, splay_tree, splay_tree_key)
(struct target_mem_desc, struct splay_tree_key_s)
(struct gomp_device_descr): Don't declare.
(num_devices_openmp): New variable.
(gomp_get_num_devices ): Use it.
(gomp_init_targets_once): New function.
(gomp_get_num_devices ): Use it.
(get_kind, gomp_copy_from_async, gomp_free_memmap)
(gomp_fini_device, gomp_register_image_for_device): New functions.
(gomp_map_vars): Add devaddrs parameter.
(gomp_update): Add mm parameter.
(gomp_init_device): Move most of it into...
(gomp_init_tables): ... this new function.
(gomp_register_images_for_device): Remove function.
(splay_compare, gomp_map_vars, gomp_unmap_vars, gomp_init_device):
Make them hidden instead of static.
(gomp_map_vars_existing, gomp_map_vars, gomp_unmap_vars)
(gomp_update, gomp_init_device, GOMP_target, GOMP_target_data)
(GOMP_target_end_data, GOMP_target_update)
(gomp_load_plugin_for_device, gomp_target_init): Update for
OpenACC changes.
* oacc-async.c: New file.
* oacc-cuda.c: Likewise.
* oacc-host.c: Likewise.
* oacc-init.c: Likewise.
* oacc-int.h: Likewise.
* oacc-mem.c: Likewise.
* oacc-parallel.c: Likewise.
* oacc-plugin.c: Likewise.
* oacc-plugin.h: Likewise.
* oacc-ptx.h: Likewise.
* openacc.f90: Likewise.
* openacc.h: Likewise.
* openacc_lib.h: Likewise.
* plugin/plugin-host.c: Likewise.
* plugin/plugin-nvptx.c: Likewise.
* libgomp-plugin.c: Likewise.
* libgomp-plugin.h: Likewise.
* libgomp_target.h: Remove file after merging content into the
former file. Update all users.
* testsuite/lib/libgomp.exp: Load libgomp-test-support.exp.
(offload_targets_s, offload_targets_s_openacc): New variables.
(check_effective_target_openacc_nvidia_accel_present)
(check_effective_target_openacc_nvidia_accel_selected): New
procedures.
(libgomp_init): Update for OpenACC changes.
* testsuite/libgomp-test-support.exp.in: New file.
* testsuite/libgomp.oacc-c++/c++.exp: Likewise.
* testsuite/libgomp.oacc-c/c.exp: Likewise.
* testsuite/libgomp.oacc-fortran/fortran.exp: Likewise.
* testsuite/libgomp.oacc-c-c++-common/abort-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/abort-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/abort-3.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/abort-4.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/acc_on_device-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/asyncwait-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/cache-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/clauses-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/clauses-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/collapse-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/collapse-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/collapse-3.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/collapse-4.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/context-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/context-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/context-3.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/context-4.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-3.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-3.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-4.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-5.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-6.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-7.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/data-already-8.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/deviceptr-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/if-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/kernels-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/kernels-empty.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-10.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-11.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-12.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-13.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-14.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-15.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-16.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-17.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-18.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-19.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-20.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-21.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-22.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-23.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-24.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-25.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-26.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-27.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-28.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-29.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-3.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-30.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-31.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-32.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-33.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-34.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-35.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-36.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-37.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-38.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-39.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-4.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-40.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-41.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-42.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-43.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-44.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-45.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-46.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-47.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-48.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-49.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-5.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-50.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-51.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-52.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-53.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-54.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-55.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-56.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-57.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-58.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-59.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-6.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-60.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-61.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-62.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-63.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-64.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-65.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-66.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-67.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-68.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-69.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-7.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-70.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-71.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-72.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-73.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-74.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-75.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-76.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-77.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-78.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-79.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-80.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-81.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-82.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-83.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-84.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-85.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-86.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-87.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-88.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-89.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-9.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-90.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-91.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/lib-92.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/nested-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/nested-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/offset-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/parallel-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/parallel-empty.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/pointer-align-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/present-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/present-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/reduction-1.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/reduction-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/reduction-3.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/reduction-4.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/reduction-5.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/reduction-initial-1.c:
Likewise.
* testsuite/libgomp.oacc-c-c++-common/subr.h: Likewise.
* testsuite/libgomp.oacc-c-c++-common/subr.ptx: Likewise.
* testsuite/libgomp.oacc-c-c++-common/timer.h: Likewise.
* testsuite/libgomp.oacc-c-c++-common/update-1-2.c: Likewise.
* testsuite/libgomp.oacc-c-c++-common/update-1.c: Likewise.
* testsuite/libgomp.oacc-fortran/abort-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/abort-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/acc_on_device-1-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/acc_on_device-1-2.f: Likewise.
* testsuite/libgomp.oacc-fortran/acc_on_device-1-3.f: Likewise.
* testsuite/libgomp.oacc-fortran/asyncwait-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/asyncwait-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/asyncwait-3.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-3.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-4.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-5.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-6.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-7.f90: Likewise.
* testsuite/libgomp.oacc-fortran/collapse-8.f90: Likewise.
* testsuite/libgomp.oacc-fortran/data-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/data-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/data-3.f90: Likewise.
* testsuite/libgomp.oacc-fortran/data-4-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/data-4.f90: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-1.f: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-2.f: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-3.f: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-4.f: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-5.f: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-6.f: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-7.f: Likewise.
* testsuite/libgomp.oacc-fortran/data-already-8.f: Likewise.
* testsuite/libgomp.oacc-fortran/lib-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/lib-10.f90: Likewise.
* testsuite/libgomp.oacc-fortran/lib-2.f: Likewise.
* testsuite/libgomp.oacc-fortran/lib-3.f: Likewise.
* testsuite/libgomp.oacc-fortran/lib-4.f90: Likewise.
* testsuite/libgomp.oacc-fortran/lib-5.f90: Likewise.
* testsuite/libgomp.oacc-fortran/lib-6.f90: Likewise.
* testsuite/libgomp.oacc-fortran/lib-7.f90: Likewise.
* testsuite/libgomp.oacc-fortran/lib-8.f90: Likewise.
* testsuite/libgomp.oacc-fortran/map-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/openacc_version-1.f: Likewise.
* testsuite/libgomp.oacc-fortran/openacc_version-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/pointer-align-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/pset-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/reduction-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/reduction-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/reduction-3.f90: Likewise.
* testsuite/libgomp.oacc-fortran/reduction-4.f90: Likewise.
* testsuite/libgomp.oacc-fortran/reduction-5.f90: Likewise.
* testsuite/libgomp.oacc-fortran/reduction-6.f90: Likewise.
* testsuite/libgomp.oacc-fortran/routine-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/routine-2.f90: Likewise.
* testsuite/libgomp.oacc-fortran/routine-3.f90: Likewise.
* testsuite/libgomp.oacc-fortran/routine-4.f90: Likewise.
* testsuite/libgomp.oacc-fortran/subarrays-1.f90: Likewise.
* testsuite/libgomp.oacc-fortran/subarrays-2.f90: Likewise.
liboffloadmic/
* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_name)
(GOMP_OFFLOAD_get_caps, GOMP_OFFLOAD_fini_device): New functions.
Co-Authored-By: Bernd Schmidt <bernds@codesourcery.com>
Co-Authored-By: Cesar Philippidis <cesar@codesourcery.com>
Co-Authored-By: Dmitry Bocharnikov <dmitry.b@samsung.com>
Co-Authored-By: Evgeny Gavrin <e.gavrin@samsung.com>
Co-Authored-By: Ilmir Usmanov <i.usmanov@samsung.com>
Co-Authored-By: Jakub Jelinek <jakub@redhat.com>
Co-Authored-By: James Norris <jnorris@codesourcery.com>
Co-Authored-By: Julian Brown <julian@codesourcery.com>
Co-Authored-By: Nathan Sidwell <nathan@codesourcery.com>
Co-Authored-By: Tobias Burnus <burnus@net-b.de>
Co-Authored-By: Tom de Vries <tom@codesourcery.com>
From-SVN: r219682
Diffstat (limited to 'gcc')
206 files changed, 14148 insertions, 908 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d40a3f0..3a27df9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,183 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + Bernd Schmidt <bernds@codesourcery.com> + Cesar Philippidis <cesar@codesourcery.com> + James Norris <jnorris@codesourcery.com> + Tom de Vries <tom@codesourcery.com> + Ilmir Usmanov <i.usmanov@samsung.com> + Dmitry Bocharnikov <dmitry.b@samsung.com> + Evgeny Gavrin <e.gavrin@samsung.com> + Jakub Jelinek <jakub@redhat.com> + + * builtin-types.def (BT_FN_VOID_INT_INT_VAR) + (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR) + (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR): + New function types. + * builtins.c: Include "gomp-constants.h". + (expand_builtin_acc_on_device): New function. + (expand_builtin, is_inexpensive_builtin): Handle + BUILT_IN_ACC_ON_DEVICE. + * builtins.def (DEF_GOACC_BUILTIN, DEF_GOACC_BUILTIN_COMPILER): + New macros. + * cgraph.c (cgraph_node::create): Consider flag_openacc next to + flag_openmp. + * config.gcc <nvptx-*> (tm_file): Add nvptx/offload.h. + <*-intelmic-* | *-intelmicemul-*> (tm_file): Add + i386/intelmic-offload.h. + * gcc.c (LINK_COMMAND_SPEC, GOMP_SELF_SPECS): For -fopenacc, link + to libgomp and its dependencies. + * config/arc/arc.h (LINK_COMMAND_SPEC): Likewise. + * config/darwin.h (LINK_COMMAND_SPEC_A): Likewise. + * config/i386/mingw32.h (GOMP_SELF_SPECS): Likewise. + * config/ia64/hpux.h (LIB_SPEC): Likewise. + * config/pa/pa-hpux11.h (LIB_SPEC): Likewise. + * config/pa/pa64-hpux.h (LIB_SPEC): Likewise. + * doc/generic.texi: Update for OpenACC changes. + * doc/gimple.texi: Likewise. + * doc/invoke.texi: Likewise. + * doc/sourcebuild.texi: Likewise. + * gimple-pretty-print.c (dump_gimple_omp_for): Handle + GF_OMP_FOR_KIND_OACC_LOOP. + (dump_gimple_omp_target): Handle GF_OMP_TARGET_KIND_OACC_KERNELS, + GF_OMP_TARGET_KIND_OACC_PARALLEL, GF_OMP_TARGET_KIND_OACC_DATA, + GF_OMP_TARGET_KIND_OACC_UPDATE, + GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA. + Dump more data. + * gimple.c: Update comments for OpenACC changes. + * gimple.def: Likewise. + * gimple.h: Likewise. + (enum gf_mask): Add GF_OMP_FOR_KIND_OACC_LOOP, + GF_OMP_TARGET_KIND_OACC_PARALLEL, GF_OMP_TARGET_KIND_OACC_KERNELS, + GF_OMP_TARGET_KIND_OACC_DATA, GF_OMP_TARGET_KIND_OACC_UPDATE, + GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA. + (gimple_omp_for_cond, gimple_omp_for_set_cond): Sort in the + appropriate place. + (is_gimple_omp_oacc, is_gimple_omp_offloaded): New functions. + * gimplify.c: Include "gomp-constants.h". + Update comments for OpenACC changes. + (is_gimple_stmt): Handle OACC_PARALLEL, OACC_KERNELS, OACC_DATA, + OACC_HOST_DATA, OACC_DECLARE, OACC_UPDATE, OACC_ENTER_DATA, + OACC_EXIT_DATA, OACC_CACHE, OACC_LOOP. + (gimplify_scan_omp_clauses, gimplify_adjust_omp_clauses): Handle + OMP_CLAUSE__CACHE_, OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT, + OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS, + OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER, + OMP_CLAUSE_VECTOR, OMP_CLAUSE_DEVICE_RESIDENT, + OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE_INDEPENDENT, OMP_CLAUSE_AUTO, + OMP_CLAUSE_SEQ. + (gimplify_adjust_omp_clauses_1, gimplify_adjust_omp_clauses): Use + GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use + OMP_CLAUSE_SET_MAP_KIND. + (gimplify_oacc_cache): New function. + (gimplify_omp_for): Handle OACC_LOOP. + (gimplify_omp_workshare): Handle OACC_KERNELS, OACC_PARALLEL, + OACC_DATA. + (gimplify_omp_target_update): Handle OACC_ENTER_DATA, + OACC_EXIT_DATA, OACC_UPDATE. + (gimplify_expr): Handle OACC_LOOP, OACC_CACHE, OACC_HOST_DATA, + OACC_DECLARE, OACC_KERNELS, OACC_PARALLEL, OACC_DATA, + OACC_ENTER_DATA, OACC_EXIT_DATA, OACC_UPDATE. + (gimplify_body): Consider flag_openacc next to flag_openmp. + * lto-streamer-out.c: Include "gomp-constants.h". + * omp-builtins.def (BUILT_IN_ACC_GET_DEVICE_TYPE) + (BUILT_IN_GOACC_DATA_START, BUILT_IN_GOACC_DATA_END) + (BUILT_IN_GOACC_ENTER_EXIT_DATA, BUILT_IN_GOACC_PARALLEL) + (BUILT_IN_GOACC_UPDATE, BUILT_IN_GOACC_WAIT) + (BUILT_IN_GOACC_GET_THREAD_NUM, BUILT_IN_GOACC_GET_NUM_THREADS) + (BUILT_IN_ACC_ON_DEVICE): New builtins. + * omp-low.c: Include "gomp-constants.h". + Update comments for OpenACC changes. + (struct omp_context): Add reduction_map, gwv_below, gwv_this + members. + (extract_omp_for_data, use_pointer_for_field, install_var_field) + (new_omp_context, delete_omp_context, scan_sharing_clauses) + (create_omp_child_function, scan_omp_for, scan_omp_target) + (check_omp_nesting_restrictions, lower_reduction_clauses) + (build_omp_regions_1, diagnose_sb_0, make_gimple_omp_edges): + Update for OpenACC changes. + (scan_sharing_clauses): Handle OMP_CLAUSE_NUM_GANGS: + OMP_CLAUSE_NUM_WORKERS: OMP_CLAUSE_VECTOR_LENGTH, + OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT, OMP_CLAUSE_GANG, + OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_DEVICE_RESIDENT, + OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE__CACHE_, OMP_CLAUSE_INDEPENDENT, + OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ. Use GOMP_MAP_* instead of + OMP_CLAUSE_MAP_*. + (expand_omp_for_static_nochunk, expand_omp_for_static_chunk): + Handle GF_OMP_FOR_KIND_OACC_LOOP. + (expand_omp_target, lower_omp_target): Handle + GF_OMP_TARGET_KIND_OACC_PARALLEL, GF_OMP_TARGET_KIND_OACC_KERNELS, + GF_OMP_TARGET_KIND_OACC_UPDATE, + GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA, + GF_OMP_TARGET_KIND_OACC_DATA. + (pass_expand_omp::execute, execute_lower_omp) + (pass_diagnose_omp_blocks::gate): Consider flag_openacc next to + flag_openmp. + (offload_symbol_decl): New variable. + (oacc_get_reduction_array_id, oacc_max_threads) + (get_offload_symbol_decl, get_base_type, lookup_oacc_reduction) + (maybe_lookup_oacc_reduction, enclosing_target_ctx) + (oacc_loop_or_target_p, oacc_lower_reduction_var_helper) + (oacc_gimple_assign, oacc_initialize_reduction_data) + (oacc_finalize_reduction_data, oacc_process_reduction_data): New + functions. + (is_targetreg_ctx): Remove function. + * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE__CACHE_, + OMP_CLAUSE_DEVICE_RESIDENT, OMP_CLAUSE_USE_DEVICE, + OMP_CLAUSE_GANG, OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT, + OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ, OMP_CLAUSE_INDEPENDENT, + OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, OMP_CLAUSE_NUM_GANGS, + OMP_CLAUSE_NUM_WORKERS, OMP_CLAUSE_VECTOR_LENGTH. + * tree.c (omp_clause_code_name, walk_tree_1): Update accordingly. + * tree.h (OMP_CLAUSE_GANG_EXPR, OMP_CLAUSE_GANG_STATIC_EXPR) + (OMP_CLAUSE_ASYNC_EXPR, OMP_CLAUSE_WAIT_EXPR) + (OMP_CLAUSE_VECTOR_EXPR, OMP_CLAUSE_WORKER_EXPR) + (OMP_CLAUSE_NUM_GANGS_EXPR, OMP_CLAUSE_NUM_WORKERS_EXPR) + (OMP_CLAUSE_VECTOR_LENGTH_EXPR): New macros. + * tree-core.h: Update comments for OpenACC changes. + (enum omp_clause_map_kind): Remove. + (struct tree_omp_clause): Change type of map_kind member from enum + omp_clause_map_kind to unsigned char. + * tree-inline.c: Update comments for OpenACC changes. + * tree-nested.c: Likewise. Include "gomp-constants.h". + (convert_nonlocal_reference_stmt, convert_local_reference_stmt) + (convert_tramp_reference_stmt, convert_gimple_call): Update for + OpenACC changes. Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use + OMP_CLAUSE_SET_MAP_KIND. + * tree-pretty-print.c: Include "gomp-constants.h". + (dump_omp_clause): Handle OMP_CLAUSE_DEVICE_RESIDENT, + OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE__CACHE_, OMP_CLAUSE_GANG, + OMP_CLAUSE_ASYNC, OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ, + OMP_CLAUSE_WAIT, OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, + OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS, + OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_INDEPENDENT. Use GOMP_MAP_* + instead of OMP_CLAUSE_MAP_*. + (dump_generic_node): Handle OACC_PARALLEL, OACC_KERNELS, + OACC_DATA, OACC_HOST_DATA, OACC_DECLARE, OACC_UPDATE, + OACC_ENTER_DATA, OACC_EXIT_DATA, OACC_CACHE, OACC_LOOP. + * tree-streamer-in.c: Include "gomp-constants.h". + (unpack_ts_omp_clause_value_fields) Use GOMP_MAP_* instead of + OMP_CLAUSE_MAP_*. Use OMP_CLAUSE_SET_MAP_KIND. + * tree-streamer-out.c: Include "gomp-constants.h". + (pack_ts_omp_clause_value_fields): Use GOMP_MAP_* instead of + OMP_CLAUSE_MAP_*. + * tree.def (OACC_PARALLEL, OACC_KERNELS, OACC_DATA) + (OACC_HOST_DATA, OACC_LOOP, OACC_CACHE, OACC_DECLARE) + (OACC_ENTER_DATA, OACC_EXIT_DATA, OACC_UPDATE): New tree codes. + * tree.c (omp_clause_num_ops): Update accordingly. + * tree.h (OMP_BODY, OMP_CLAUSES, OMP_LOOP_CHECK, OMP_CLAUSE_SIZE): + Likewise. + (OACC_PARALLEL_BODY, OACC_PARALLEL_CLAUSES, OACC_KERNELS_BODY) + (OACC_KERNELS_CLAUSES, OACC_DATA_BODY, OACC_DATA_CLAUSES) + (OACC_HOST_DATA_BODY, OACC_HOST_DATA_CLAUSES, OACC_CACHE_CLAUSES) + (OACC_DECLARE_CLAUSES, OACC_ENTER_DATA_CLAUSES) + (OACC_EXIT_DATA_CLAUSES, OACC_UPDATE_CLAUSES) + (OACC_KERNELS_COMBINED, OACC_PARALLEL_COMBINED): New macros. + * tree.h (OMP_CLAUSE_MAP_KIND): Cast it to enum gomp_map_kind. + (OMP_CLAUSE_SET_MAP_KIND): New macro. + * varpool.c (varpool_node::get_create): Consider flag_openacc next + to flag_openmp. + * config/i386/intelmic-offload.h: New file. + * config/nvptx/offload.h: Likewise. + 2015-01-15 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> * explow.h: Remove duplicate contents. diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 93efb49..c130f7d2 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,8 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + + * gcc-interface/utils.c (DEF_FUNCTION_TYPE_VAR_8) + (DEF_FUNCTION_TYPE_VAR_12): New macros. + 2015-01-09 Michael Collison <michael.collison@linaro.org> * gcc-interface/cuintp.c: Include hash-set.h, machmode.h, diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index b62c7d4..477e39b 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -5339,6 +5339,12 @@ enum c_builtin_type #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ NAME, +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + NAME, +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \ + NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "builtin-types.def" #undef DEF_PRIMITIVE_TYPE @@ -5357,6 +5363,8 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE BT_LAST }; @@ -5462,6 +5470,14 @@ install_builtin_function_types (void) def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \ + def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10, ARG11, ARG12); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); @@ -5483,6 +5499,8 @@ install_builtin_function_types (void) #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE builtin_types[(int) BT_LAST] = NULL_TREE; } diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index 34cec43..3412677 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -568,6 +568,8 @@ DEF_FUNCTION_TYPE_VAR_2 (BT_FN_INT_INT_CONST_STRING_VAR, BT_INT, BT_INT, BT_CONST_STRING) DEF_FUNCTION_TYPE_VAR_2 (BT_FN_PTR_CONST_PTR_SIZE_VAR, BT_PTR, BT_CONST_PTR, BT_SIZE) +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_INT_INT_VAR, BT_VOID, + BT_INT, BT_INT) DEF_FUNCTION_TYPE_VAR_3 (BT_FN_INT_STRING_SIZE_CONST_STRING_VAR, BT_INT, BT_STRING, BT_SIZE, BT_CONST_STRING) @@ -586,6 +588,15 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR, DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_INT_INT_INT_INT_VAR, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT) +DEF_FUNCTION_TYPE_VAR_8 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR, + BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, + BT_PTR, BT_INT, BT_INT) + +DEF_FUNCTION_TYPE_VAR_12 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR, + BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE, + BT_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT, BT_INT, + BT_INT, BT_INT) + DEF_POINTER_TYPE (BT_PTR_FN_VOID_VAR, BT_FN_VOID_VAR) DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_FN_VOID_VAR_PTR_SIZE, BT_PTR, BT_PTR_FN_VOID_VAR, BT_PTR, BT_SIZE) diff --git a/gcc/builtins.c b/gcc/builtins.c index 737023b..9a6a11b 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see #include "cgraph.h" #include "tree-chkp.h" #include "rtl-chkp.h" +#include "gomp-constants.h" static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t)); @@ -5903,6 +5904,47 @@ expand_stack_save (void) return ret; } + +/* Expand OpenACC acc_on_device. + + This has to happen late (that is, not in early folding; expand_builtin_*, + rather than fold_builtin_*), as we have to act differently for host and + acceleration device (ACCEL_COMPILER conditional). */ + +static rtx +expand_builtin_acc_on_device (tree exp, rtx target) +{ + if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE)) + return NULL_RTX; + + tree arg = CALL_EXPR_ARG (exp, 0); + + /* Return (arg == v1 || arg == v2) ? 1 : 0. */ + machine_mode v_mode = TYPE_MODE (TREE_TYPE (arg)); + rtx v = expand_normal (arg), v1, v2; +#ifdef ACCEL_COMPILER + v1 = GEN_INT (GOMP_DEVICE_NOT_HOST); + v2 = GEN_INT (ACCEL_COMPILER_acc_device); +#else + v1 = GEN_INT (GOMP_DEVICE_NONE); + v2 = GEN_INT (GOMP_DEVICE_HOST); +#endif + machine_mode target_mode = TYPE_MODE (integer_type_node); + if (!REG_P (target) || GET_MODE (target) != target_mode) + target = gen_reg_rtx (target_mode); + emit_move_insn (target, const1_rtx); + rtx_code_label *done_label = gen_label_rtx (); + do_compare_rtx_and_jump (v, v1, EQ, false, v_mode, NULL_RTX, + NULL_RTX, done_label, PROB_EVEN); + do_compare_rtx_and_jump (v, v2, EQ, false, v_mode, NULL_RTX, + NULL_RTX, done_label, PROB_EVEN); + emit_move_insn (target, const0_rtx); + emit_label (done_label); + + return target; +} + + /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient (and in mode MODE if that's convenient). @@ -7041,6 +7083,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, error ("Your target platform does not support -fcheck-pointer-bounds"); break; + case BUILT_IN_ACC_ON_DEVICE: + target = expand_builtin_acc_on_device (exp, target); + if (target) + return target; + break; + default: /* just do library call, if unknown builtin */ break; } @@ -12478,6 +12526,7 @@ is_inexpensive_builtin (tree decl) case BUILT_IN_LABS: case BUILT_IN_LLABS: case BUILT_IN_PREFETCH: + case BUILT_IN_ACC_ON_DEVICE: return true; default: diff --git a/gcc/builtins.def b/gcc/builtins.def index 5a7ed10..e3153bf 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -146,10 +146,20 @@ along with GCC; see the file COPYING3. If not see DEF_BUILTIN (ENUM, NAME, BUILT_IN_NORMAL, BT_LAST, BT_LAST, false, false, \ false, ATTR_LAST, false, false) -/* Builtin used by the implementation of GNU OpenMP. None of these are - actually implemented in the compiler; they're all in libgomp. */ +/* Builtin used by the implementation of OpenACC and OpenMP. Few of these are + actually implemented in the compiler; most are in libgomp. */ /* These builtins also need to be enabled in offloading compilers invoked from mkoffload; for that purpose, we're checking the -foffload-abi flag here. */ +#undef DEF_GOACC_BUILTIN +#define DEF_GOACC_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ + DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ + false, true, true, ATTRS, false, \ + (flag_openacc \ + || flag_offload_abi != OFFLOAD_ABI_UNSET)) +#undef DEF_GOACC_BUILTIN_COMPILER +#define DEF_GOACC_BUILTIN_COMPILER(ENUM, NAME, TYPE, ATTRS) \ + DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ + flag_openacc, true, true, ATTRS, false, true) #undef DEF_GOMP_BUILTIN #define DEF_GOMP_BUILTIN(ENUM, NAME, TYPE, ATTRS) \ DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, \ @@ -897,7 +907,7 @@ DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST) /* Synchronization Primitives. */ #include "sync-builtins.def" -/* OpenMP builtins. */ +/* Offloading and Multi Processing builtins. */ #include "omp-builtins.def" /* Cilk keywords builtins. */ diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 9764045..e0ad215 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,41 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + Bernd Schmidt <bernds@codesourcery.com> + James Norris <jnorris@codesourcery.com> + Cesar Philippidis <cesar@codesourcery.com> + Ilmir Usmanov <i.usmanov@samsung.com> + Jakub Jelinek <jakub@redhat.com> + + * c.opt (fopenacc): New option. + * c-cppbuiltin.c (c_cpp_builtins): Conditionally define _OPENACC. + * c-common.c (DEF_FUNCTION_TYPE_VAR_8, DEF_FUNCTION_TYPE_VAR_12): + New macros. + * c-common.h (c_finish_oacc_wait): New prototype. + * c-omp.c: Include "omp-low.h" and "gomp-constants.h". + (c_finish_oacc_wait): New function. + * c-pragma.c (oacc_pragmas): New variable. + (c_pp_lookup_pragma, init_pragma): Handle it. + * c-pragma.h (enum pragma_kind): Add PRAGMA_OACC_CACHE, + PRAGMA_OACC_DATA, PRAGMA_OACC_ENTER_DATA, PRAGMA_OACC_EXIT_DATA, + PRAGMA_OACC_KERNELS, PRAGMA_OACC_LOOP, PRAGMA_OACC_PARALLEL, + PRAGMA_OACC_UPDATE, PRAGMA_OACC_WAIT. + (enum pragma_omp_clause): Add PRAGMA_OACC_CLAUSE_ASYNC, + PRAGMA_OACC_CLAUSE_AUTO, PRAGMA_OACC_CLAUSE_COLLAPSE, + PRAGMA_OACC_CLAUSE_COPY, PRAGMA_OACC_CLAUSE_COPYIN, + PRAGMA_OACC_CLAUSE_COPYOUT, PRAGMA_OACC_CLAUSE_CREATE, + PRAGMA_OACC_CLAUSE_DELETE, PRAGMA_OACC_CLAUSE_DEVICE, + PRAGMA_OACC_CLAUSE_DEVICEPTR, PRAGMA_OACC_CLAUSE_FIRSTPRIVATE, + PRAGMA_OACC_CLAUSE_GANG, PRAGMA_OACC_CLAUSE_HOST, + PRAGMA_OACC_CLAUSE_IF, PRAGMA_OACC_CLAUSE_NUM_GANGS, + PRAGMA_OACC_CLAUSE_NUM_WORKERS, PRAGMA_OACC_CLAUSE_PRESENT, + PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY, + PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN, + PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT, + PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE, PRAGMA_OACC_CLAUSE_PRIVATE, + PRAGMA_OACC_CLAUSE_REDUCTION, PRAGMA_OACC_CLAUSE_SELF, + PRAGMA_OACC_CLAUSE_SEQ, PRAGMA_OACC_CLAUSE_VECTOR, + PRAGMA_OACC_CLAUSE_VECTOR_LENGTH, PRAGMA_OACC_CLAUSE_WAIT, + PRAGMA_OACC_CLAUSE_WORKER. + 2015-01-14 Marcos Diaz <marcos.diaz@tallertechnologies.com> * c-cppbuiltin.c (c_cpp_builtins): New cpp define __SSP_EXPLICIT__ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 054f5a0..eb132c5 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5234,6 +5234,11 @@ enum c_builtin_type #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ NAME, +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, \ + ARG12) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "builtin-types.def" #undef DEF_PRIMITIVE_TYPE @@ -5252,6 +5257,8 @@ enum c_builtin_type #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE BT_LAST }; @@ -5344,6 +5351,14 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 1, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \ + def_fn_type (ENUM, RETURN, 1, 12, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10, ARG11, ARG12); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); @@ -5365,6 +5380,8 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node) #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE builtin_types[(int) BT_LAST] = NULL_TREE; diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index bc2cdee..5b2c5ab 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1248,6 +1248,7 @@ extern void c_finish_omp_taskwait (location_t); extern void c_finish_omp_taskyield (location_t); extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree, tree, tree, tree); +extern tree c_finish_oacc_wait (location_t, tree, tree); extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask, tree, tree *); extern tree c_omp_declare_simd_clauses_to_numbers (tree, tree); diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index 0b00d59..1936592 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -1221,6 +1221,9 @@ c_cpp_builtins (cpp_reader *pfile) else if (flag_stack_protect == 1) cpp_define (pfile, "__SSP__=1"); + if (flag_openacc) + cpp_define (pfile, "_OPENACC=201306"); + if (flag_openmp) cpp_define (pfile, "_OPENMP=201307"); diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 0523b4c..8715045 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -1,4 +1,4 @@ -/* This file contains routines to construct GNU OpenMP constructs, +/* This file contains routines to construct OpenACC and OpenMP constructs, called from parsing in the C and C++ front ends. Copyright (C) 2005-2015 Free Software Foundation, Inc. @@ -39,8 +39,48 @@ along with GCC; see the file COPYING3. If not see #include "c-pragma.h" #include "gimple-expr.h" #include "langhooks.h" +#include "omp-low.h" +#include "gomp-constants.h" +/* Complete a #pragma oacc wait construct. LOC is the location of + the #pragma. */ + +tree +c_finish_oacc_wait (location_t loc, tree parms, tree clauses) +{ + const int nparms = list_length (parms); + tree stmt, t; + vec<tree, va_gc> *args; + + vec_alloc (args, nparms + 2); + stmt = builtin_decl_explicit (BUILT_IN_GOACC_WAIT); + + if (find_omp_clause (clauses, OMP_CLAUSE_ASYNC)) + t = OMP_CLAUSE_ASYNC_EXPR (clauses); + else + t = build_int_cst (integer_type_node, GOMP_ASYNC_SYNC); + + args->quick_push (t); + args->quick_push (build_int_cst (integer_type_node, nparms)); + + for (t = parms; t; t = TREE_CHAIN (t)) + { + if (TREE_CODE (OMP_CLAUSE_WAIT_EXPR (t)) == INTEGER_CST) + args->quick_push (build_int_cst (integer_type_node, + TREE_INT_CST_LOW (OMP_CLAUSE_WAIT_EXPR (t)))); + else + args->quick_push (OMP_CLAUSE_WAIT_EXPR (t)); + } + + stmt = build_call_expr_loc_vec (loc, stmt, args); + add_stmt (stmt); + + vec_free (args); + + return stmt; +} + /* Complete a #pragma omp master construct. STMT is the structured-block that follows the pragma. LOC is the l*/ @@ -303,7 +343,7 @@ c_finish_omp_flush (location_t loc) } -/* Check and canonicalize #pragma omp for increment expression. +/* Check and canonicalize OMP_FOR increment expression. Helper function for c_finish_omp_for. */ static tree @@ -391,7 +431,7 @@ c_omp_for_incr_canonicalize_ptr (location_t loc, tree decl, tree incr) return incr; } -/* Validate and emit code for the OpenMP directive #pragma omp for. +/* Validate and generate OMP_FOR. DECLV is a vector of iteration variables, for each collapsed loop. INITV, CONDV and INCRV are vectors containing initialization expressions, controlling predicates and increment expressions. diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 16c70e5..718a310 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1190,6 +1190,17 @@ typedef struct static vec<pragma_ns_name> registered_pp_pragmas; struct omp_pragma_def { const char *name; unsigned int id; }; +static const struct omp_pragma_def oacc_pragmas[] = { + { "cache", PRAGMA_OACC_CACHE }, + { "data", PRAGMA_OACC_DATA }, + { "enter", PRAGMA_OACC_ENTER_DATA }, + { "exit", PRAGMA_OACC_EXIT_DATA }, + { "kernels", PRAGMA_OACC_KERNELS }, + { "loop", PRAGMA_OACC_LOOP }, + { "parallel", PRAGMA_OACC_PARALLEL }, + { "update", PRAGMA_OACC_UPDATE }, + { "wait", PRAGMA_OACC_WAIT } +}; static const struct omp_pragma_def omp_pragmas[] = { { "atomic", PRAGMA_OMP_ATOMIC }, { "barrier", PRAGMA_OMP_BARRIER }, @@ -1222,11 +1233,20 @@ static const struct omp_pragma_def omp_pragmas_simd[] = { void c_pp_lookup_pragma (unsigned int id, const char **space, const char **name) { + const int n_oacc_pragmas = sizeof (oacc_pragmas) / sizeof (*oacc_pragmas); const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); const int n_omp_pragmas_simd = sizeof (omp_pragmas_simd) / sizeof (*omp_pragmas); int i; + for (i = 0; i < n_oacc_pragmas; ++i) + if (oacc_pragmas[i].id == id) + { + *space = "acc"; + *name = oacc_pragmas[i].name; + return; + } + for (i = 0; i < n_omp_pragmas; ++i) if (omp_pragmas[i].id == id) { @@ -1393,6 +1413,17 @@ c_invoke_pragma_handler (unsigned int id) void init_pragma (void) { + if (flag_openacc) + { + const int n_oacc_pragmas + = sizeof (oacc_pragmas) / sizeof (*oacc_pragmas); + int i; + + for (i = 0; i < n_oacc_pragmas; ++i) + cpp_register_deferred_pragma (parse_in, "acc", oacc_pragmas[i].name, + oacc_pragmas[i].id, true, true); + } + if (flag_openmp) { const int n_omp_pragmas = sizeof (omp_pragmas) / sizeof (*omp_pragmas); diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index cd9fb27..eff94c1 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -27,6 +27,15 @@ along with GCC; see the file COPYING3. If not see typedef enum pragma_kind { PRAGMA_NONE = 0, + PRAGMA_OACC_CACHE, + PRAGMA_OACC_DATA, + PRAGMA_OACC_ENTER_DATA, + PRAGMA_OACC_EXIT_DATA, + PRAGMA_OACC_KERNELS, + PRAGMA_OACC_LOOP, + PRAGMA_OACC_PARALLEL, + PRAGMA_OACC_UPDATE, + PRAGMA_OACC_WAIT, PRAGMA_OMP_ATOMIC, PRAGMA_OMP_BARRIER, PRAGMA_OMP_CANCEL, @@ -65,7 +74,7 @@ typedef enum pragma_kind { } pragma_kind; -/* All clauses defined by OpenMP 2.5, 3.0, 3.1 and 4.0. +/* All clauses defined by OpenACC 2.0, and OpenMP 2.5, 3.0, 3.1, and 4.0. Used internally by both C and C++ parsers. */ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_NONE = 0, @@ -118,7 +127,38 @@ typedef enum pragma_omp_clause { PRAGMA_CILK_CLAUSE_FIRSTPRIVATE = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, PRAGMA_CILK_CLAUSE_LASTPRIVATE = PRAGMA_OMP_CLAUSE_LASTPRIVATE, PRAGMA_CILK_CLAUSE_REDUCTION = PRAGMA_OMP_CLAUSE_REDUCTION, - PRAGMA_CILK_CLAUSE_UNIFORM = PRAGMA_OMP_CLAUSE_UNIFORM + PRAGMA_CILK_CLAUSE_UNIFORM = PRAGMA_OMP_CLAUSE_UNIFORM, + + /* Clauses for OpenACC. */ + PRAGMA_OACC_CLAUSE_ASYNC = PRAGMA_CILK_CLAUSE_VECTORLENGTH + 1, + PRAGMA_OACC_CLAUSE_AUTO, + PRAGMA_OACC_CLAUSE_COPY, + PRAGMA_OACC_CLAUSE_COPYOUT, + PRAGMA_OACC_CLAUSE_CREATE, + PRAGMA_OACC_CLAUSE_DELETE, + PRAGMA_OACC_CLAUSE_DEVICEPTR, + PRAGMA_OACC_CLAUSE_GANG, + PRAGMA_OACC_CLAUSE_HOST, + PRAGMA_OACC_CLAUSE_NUM_GANGS, + PRAGMA_OACC_CLAUSE_NUM_WORKERS, + PRAGMA_OACC_CLAUSE_PRESENT, + PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY, + PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN, + PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT, + PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE, + PRAGMA_OACC_CLAUSE_SELF, + PRAGMA_OACC_CLAUSE_SEQ, + PRAGMA_OACC_CLAUSE_VECTOR, + PRAGMA_OACC_CLAUSE_VECTOR_LENGTH, + PRAGMA_OACC_CLAUSE_WAIT, + PRAGMA_OACC_CLAUSE_WORKER, + PRAGMA_OACC_CLAUSE_COLLAPSE = PRAGMA_OMP_CLAUSE_COLLAPSE, + PRAGMA_OACC_CLAUSE_COPYIN = PRAGMA_OMP_CLAUSE_COPYIN, + PRAGMA_OACC_CLAUSE_DEVICE = PRAGMA_OMP_CLAUSE_DEVICE, + PRAGMA_OACC_CLAUSE_FIRSTPRIVATE = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, + PRAGMA_OACC_CLAUSE_IF = PRAGMA_OMP_CLAUSE_IF, + PRAGMA_OACC_CLAUSE_PRIVATE = PRAGMA_OMP_CLAUSE_PRIVATE, + PRAGMA_OACC_CLAUSE_REDUCTION = PRAGMA_OMP_CLAUSE_REDUCTION } pragma_omp_clause; extern struct cpp_reader* parse_in; diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index e61fc56..62b6c685 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1283,6 +1283,10 @@ fobjc-std=objc1 ObjC ObjC++ Var(flag_objc1_only) Conform to the Objective-C 1.0 language as implemented in GCC 4.0 +fopenacc +C ObjC C++ ObjC++ Var(flag_openacc) +Enable OpenACC + fopenmp C ObjC C++ ObjC++ Var(flag_openmp) Enable OpenMP (implies -frecursive in Fortran) diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index f42f53b..4652409 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,54 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + Bernd Schmidt <bernds@codesourcery.com> + Cesar Philippidis <cesar@codesourcery.com> + James Norris <jnorris@codesourcery.com> + Jakub Jelinek <jakub@redhat.com> + Ilmir Usmanov <i.usmanov@samsung.com> + + * c-parser.c: Include "gomp-constants.h". + (c_parser_omp_clause_map): Use enum gomp_map_kind instead of enum + omp_clause_map_kind. Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. + Use OMP_CLAUSE_SET_MAP_KIND. + (c_parser_pragma): Handle PRAGMA_OACC_ENTER_DATA, + PRAGMA_OACC_EXIT_DATA, PRAGMA_OACC_UPDATE. + (c_parser_omp_construct): Handle PRAGMA_OACC_CACHE, + PRAGMA_OACC_DATA, PRAGMA_OACC_KERNELS, PRAGMA_OACC_LOOP, + PRAGMA_OACC_PARALLEL, PRAGMA_OACC_WAIT. + (c_parser_omp_clause_name): Handle "auto", "async", "copy", + "copyout", "create", "delete", "deviceptr", "gang", "host", + "num_gangs", "num_workers", "present", "present_or_copy", "pcopy", + "present_or_copyin", "pcopyin", "present_or_copyout", "pcopyout", + "present_or_create", "pcreate", "seq", "self", "vector", + "vector_length", "wait", "worker". + (OACC_DATA_CLAUSE_MASK, OACC_KERNELS_CLAUSE_MASK) + (OACC_ENTER_DATA_CLAUSE_MASK, OACC_EXIT_DATA_CLAUSE_MASK) + (OACC_LOOP_CLAUSE_MASK, OACC_PARALLEL_CLAUSE_MASK) + (OACC_UPDATE_CLAUSE_MASK, OACC_WAIT_CLAUSE_MASK): New macros. + (c_parser_omp_variable_list): Handle OMP_CLAUSE__CACHE_. + (c_parser_oacc_wait_list, c_parser_oacc_data_clause) + (c_parser_oacc_data_clause_deviceptr) + (c_parser_omp_clause_num_gangs, c_parser_omp_clause_num_workers) + (c_parser_oacc_clause_async, c_parser_oacc_clause_wait) + (c_parser_omp_clause_vector_length, c_parser_oacc_all_clauses) + (c_parser_oacc_cache, c_parser_oacc_data, c_parser_oacc_kernels) + (c_parser_oacc_enter_exit_data, c_parser_oacc_loop) + (c_parser_oacc_parallel, c_parser_oacc_update) + (c_parser_oacc_wait): New functions. + * c-tree.h (c_finish_oacc_parallel, c_finish_oacc_kernels) + (c_finish_oacc_data): New prototypes. + * c-typeck.c: Include "gomp-constants.h". + (handle_omp_array_sections): Handle GOMP_MAP_FORCE_DEVICEPTR. Use + GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use + OMP_CLAUSE_SET_MAP_KIND. + (c_finish_oacc_parallel, c_finish_oacc_kernels) + (c_finish_oacc_data): New functions. + (c_finish_omp_clauses): Handle OMP_CLAUSE__CACHE_, + OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS, + OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_ASYNC, OMP_CLAUSE_WAIT, + OMP_CLAUSE_AUTO, OMP_CLAUSE_SEQ, OMP_CLAUSE_GANG, + OMP_CLAUSE_WORKER, OMP_CLAUSE_VECTOR, and OMP_CLAUSE_MAP's + GOMP_MAP_FORCE_DEVICEPTR. + 2015-01-09 Michael Collison <michael.collison@linaro.org> * c-array-notation.c: Include hash-set.h, machmode.h, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d309465..665ee42 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -81,6 +81,7 @@ along with GCC; see the file COPYING3. If not see #include "plugin.h" #include "omp-low.h" #include "builtins.h" +#include "gomp-constants.h" /* Initialization routine for this file. */ @@ -1249,10 +1250,15 @@ static vec<tree, va_gc> *c_parser_expr_list (c_parser *, bool, bool, vec<tree, va_gc> **, location_t *, tree *, vec<location_t> *, unsigned int * = NULL); +static void c_parser_oacc_enter_exit_data (c_parser *, bool); +static void c_parser_oacc_update (c_parser *); +static tree c_parser_oacc_loop (location_t, c_parser *, char *); static void c_parser_omp_construct (c_parser *); static void c_parser_omp_threadprivate (c_parser *); static void c_parser_omp_barrier (c_parser *); static void c_parser_omp_flush (c_parser *); +static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, + tree, tree *); static void c_parser_omp_taskwait (c_parser *); static void c_parser_omp_taskyield (c_parser *); static void c_parser_omp_cancel (c_parser *); @@ -4492,6 +4498,14 @@ c_parser_initval (c_parser *parser, struct c_expr *after, Although they are erroneous if the labels declared aren't defined, is it useful for the syntax to be this way? + OpenACC: + + block-item: + openacc-directive + + openacc-directive: + update-directive + OpenMP: block-item: @@ -4838,6 +4852,29 @@ c_parser_label (c_parser *parser) @throw expression ; @throw ; + OpenACC: + + statement: + openacc-construct + + openacc-construct: + parallel-construct + kernels-construct + data-construct + loop-construct + + parallel-construct: + parallel-directive structured-block + + kernels-construct: + kernels-directive structured-block + + data-construct: + data-directive structured-block + + loop-construct: + loop-directive structured-block + OpenMP: statement: @@ -9570,6 +9607,25 @@ c_parser_pragma (c_parser *parser, enum pragma_context context) switch (id) { + case PRAGMA_OACC_ENTER_DATA: + c_parser_oacc_enter_exit_data (parser, true); + return false; + + case PRAGMA_OACC_EXIT_DATA: + c_parser_oacc_enter_exit_data (parser, false); + return false; + + case PRAGMA_OACC_UPDATE: + if (context != pragma_compound) + { + if (context == pragma_stmt) + c_parser_error (parser, "%<#pragma acc update%> may only be " + "used in compound statements"); + goto bad_stmt; + } + c_parser_oacc_update (parser); + return false; + case PRAGMA_OMP_BARRIER: if (context != pragma_compound) { @@ -9772,7 +9828,7 @@ c_parser_pragma_pch_preprocess (c_parser *parser) c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name)); } -/* OpenMP 2.5 / 3.0 / 3.1 / 4.0 parsing routines. */ +/* OpenACC and OpenMP parsing routines. */ /* Returns name of the next clause. If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and @@ -9784,7 +9840,9 @@ c_parser_omp_clause_name (c_parser *parser) { pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE; - if (c_parser_next_token_is_keyword (parser, RID_IF)) + if (c_parser_next_token_is_keyword (parser, RID_AUTO)) + result = PRAGMA_OACC_CLAUSE_AUTO; + else if (c_parser_next_token_is_keyword (parser, RID_IF)) result = PRAGMA_OMP_CLAUSE_IF; else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) result = PRAGMA_OMP_CLAUSE_DEFAULT; @@ -9799,20 +9857,32 @@ c_parser_omp_clause_name (c_parser *parser) case 'a': if (!strcmp ("aligned", p)) result = PRAGMA_OMP_CLAUSE_ALIGNED; + else if (!strcmp ("async", p)) + result = PRAGMA_OACC_CLAUSE_ASYNC; break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; + else if (!strcmp ("copy", p)) + result = PRAGMA_OACC_CLAUSE_COPY; else if (!strcmp ("copyin", p)) result = PRAGMA_OMP_CLAUSE_COPYIN; + else if (!strcmp ("copyout", p)) + result = PRAGMA_OACC_CLAUSE_COPYOUT; else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; + else if (!strcmp ("create", p)) + result = PRAGMA_OACC_CLAUSE_CREATE; break; case 'd': - if (!strcmp ("depend", p)) + if (!strcmp ("delete", p)) + result = PRAGMA_OACC_CLAUSE_DELETE; + else if (!strcmp ("depend", p)) result = PRAGMA_OMP_CLAUSE_DEPEND; else if (!strcmp ("device", p)) result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("deviceptr", p)) + result = PRAGMA_OACC_CLAUSE_DEVICEPTR; else if (!strcmp ("dist_schedule", p)) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; @@ -9824,6 +9894,14 @@ c_parser_omp_clause_name (c_parser *parser) else if (!strcmp ("from", p)) result = PRAGMA_OMP_CLAUSE_FROM; break; + case 'g': + if (!strcmp ("gang", p)) + result = PRAGMA_OACC_CLAUSE_GANG; + break; + case 'h': + if (!strcmp ("host", p)) + result = PRAGMA_OACC_CLAUSE_HOST; + break; case 'i': if (!strcmp ("inbranch", p)) result = PRAGMA_OMP_CLAUSE_INBRANCH; @@ -9847,10 +9925,14 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; + else if (!strcmp ("num_gangs", p)) + result = PRAGMA_OACC_CLAUSE_NUM_GANGS; else if (!strcmp ("num_teams", p)) result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; + else if (!strcmp ("num_workers", p)) + result = PRAGMA_OACC_CLAUSE_NUM_WORKERS; else if (flag_cilkplus && !strcmp ("nomask", p)) result = PRAGMA_CILK_CLAUSE_NOMASK; break; @@ -9861,6 +9943,20 @@ c_parser_omp_clause_name (c_parser *parser) case 'p': if (!strcmp ("parallel", p)) result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("present", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT; + else if (!strcmp ("present_or_copy", p) + || !strcmp ("pcopy", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY; + else if (!strcmp ("present_or_copyin", p) + || !strcmp ("pcopyin", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN; + else if (!strcmp ("present_or_copyout", p) + || !strcmp ("pcopyout", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT; + else if (!strcmp ("present_or_create", p) + || !strcmp ("pcreate", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE; else if (!strcmp ("private", p)) result = PRAGMA_OMP_CLAUSE_PRIVATE; else if (!strcmp ("proc_bind", p)) @@ -9877,10 +9973,14 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_SCHEDULE; else if (!strcmp ("sections", p)) result = PRAGMA_OMP_CLAUSE_SECTIONS; + else if (!strcmp ("seq", p)) + result = PRAGMA_OACC_CLAUSE_SEQ; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; else if (!strcmp ("simdlen", p)) result = PRAGMA_OMP_CLAUSE_SIMDLEN; + else if (!strcmp ("self", p)) + result = PRAGMA_OACC_CLAUSE_SELF; break; case 't': if (!strcmp ("taskgroup", p)) @@ -9897,9 +9997,19 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_UNTIED; break; case 'v': - if (flag_cilkplus && !strcmp ("vectorlength", p)) + if (!strcmp ("vector", p)) + result = PRAGMA_OACC_CLAUSE_VECTOR; + else if (!strcmp ("vector_length", p)) + result = PRAGMA_OACC_CLAUSE_VECTOR_LENGTH; + else if (flag_cilkplus && !strcmp ("vectorlength", p)) result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; break; + case 'w': + if (!strcmp ("wait", p)) + result = PRAGMA_OACC_CLAUSE_WAIT; + else if (!strcmp ("worker", p)) + result = PRAGMA_OACC_CLAUSE_WORKER; + break; } } @@ -9926,7 +10036,57 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code, } } -/* OpenMP 2.5: +/* OpenACC 2.0 + Parse wait clause or wait directive parameters. */ + +static tree +c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) +{ + vec<tree, va_gc> *args; + tree t, args_tree; + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return list; + + args = c_parser_expr_list (parser, false, true, NULL, NULL, NULL, NULL); + + if (args->length () == 0) + { + c_parser_error (parser, "expected integer expression before ')'"); + release_tree_vector (args); + return list; + } + + args_tree = build_tree_list_vec (args); + + for (t = args_tree; t; t = TREE_CHAIN (t)) + { + tree targ = TREE_VALUE (t); + + if (targ != error_mark_node) + { + if (!INTEGRAL_TYPE_P (TREE_TYPE (targ))) + { + c_parser_error (parser, "expression must be integral"); + targ = error_mark_node; + } + else + { + tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); + + OMP_CLAUSE_DECL (c) = targ; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + } + } + + release_tree_vector (args); + c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + return list; +} + +/* OpenACC 2.0, OpenMP 2.5: variable-list: identifier variable-list , identifier @@ -9967,6 +10127,14 @@ c_parser_omp_variable_list (c_parser *parser, { switch (kind) { + case OMP_CLAUSE__CACHE_: + if (c_parser_peek_token (parser)->type != CPP_OPEN_SQUARE) + { + c_parser_error (parser, "expected %<[%>"); + t = error_mark_node; + break; + } + /* FALL THROUGH. */ case OMP_CLAUSE_MAP: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: @@ -10005,6 +10173,26 @@ c_parser_omp_variable_list (c_parser *parser, t = error_mark_node; break; } + + if (kind == OMP_CLAUSE__CACHE_) + { + if (TREE_CODE (low_bound) != INTEGER_CST + && !TREE_READONLY (low_bound)) + { + error_at (clause_loc, + "%qD is not a constant", low_bound); + t = error_mark_node; + } + + if (TREE_CODE (length) != INTEGER_CST + && !TREE_READONLY (length)) + { + error_at (clause_loc, + "%qD is not a constant", length); + t = error_mark_node; + } + } + t = tree_cons (low_bound, length, t); } break; @@ -10033,7 +10221,7 @@ c_parser_omp_variable_list (c_parser *parser, } /* Similarly, but expect leading and trailing parenthesis. This is a very - common case for omp clauses. */ + common case for OpenACC and OpenMP clauses. */ static tree c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, @@ -10050,7 +10238,119 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, return list; } -/* OpenMP 3.0: +/* OpenACC 2.0: + copy ( variable-list ) + copyin ( variable-list ) + copyout ( variable-list ) + create ( variable-list ) + delete ( variable-list ) + present ( variable-list ) + present_or_copy ( variable-list ) + pcopy ( variable-list ) + present_or_copyin ( variable-list ) + pcopyin ( variable-list ) + present_or_copyout ( variable-list ) + pcopyout ( variable-list ) + present_or_create ( variable-list ) + pcreate ( variable-list ) */ + +static tree +c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, + tree list) +{ + enum gomp_map_kind kind; + switch (c_kind) + { + case PRAGMA_OACC_CLAUSE_COPY: + kind = GOMP_MAP_FORCE_TOFROM; + break; + case PRAGMA_OACC_CLAUSE_COPYIN: + kind = GOMP_MAP_FORCE_TO; + break; + case PRAGMA_OACC_CLAUSE_COPYOUT: + kind = GOMP_MAP_FORCE_FROM; + break; + case PRAGMA_OACC_CLAUSE_CREATE: + kind = GOMP_MAP_FORCE_ALLOC; + break; + case PRAGMA_OACC_CLAUSE_DELETE: + kind = GOMP_MAP_FORCE_DEALLOC; + break; + case PRAGMA_OACC_CLAUSE_DEVICE: + kind = GOMP_MAP_FORCE_TO; + break; + case PRAGMA_OACC_CLAUSE_HOST: + case PRAGMA_OACC_CLAUSE_SELF: + kind = GOMP_MAP_FORCE_FROM; + break; + case PRAGMA_OACC_CLAUSE_PRESENT: + kind = GOMP_MAP_FORCE_PRESENT; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY: + kind = GOMP_MAP_TOFROM; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN: + kind = GOMP_MAP_TO; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT: + kind = GOMP_MAP_FROM; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE: + kind = GOMP_MAP_ALLOC; + break; + default: + gcc_unreachable (); + } + tree nl, c; + nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_SET_MAP_KIND (c, kind); + + return nl; +} + +/* OpenACC 2.0: + deviceptr ( variable-list ) */ + +static tree +c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree vars, t; + + /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic + c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR, + variable-list must only allow for pointer variables. */ + vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL); + for (t = vars; t && t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* FIXME diagnostics: Ideally we should keep individual + locations for all the variables in the var list to make the + following errors more precise. Perhaps + c_parser_omp_var_list_parens() should construct a list of + locations to go along with the var list. */ + + if (TREE_CODE (v) != VAR_DECL) + error_at (loc, "%qD is not a variable", v); + else if (TREE_TYPE (v) == error_mark_node) + ; + else if (!POINTER_TYPE_P (TREE_TYPE (v))) + error_at (loc, "%qD is not a pointer variable", v); + + tree u = build_omp_clause (loc, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (u, GOMP_MAP_FORCE_DEVICEPTR); + OMP_CLAUSE_DECL (u) = v; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + + return list; +} + +/* OpenACC 2.0, OpenMP 3.0: collapse ( constant-expression ) */ static tree @@ -10193,7 +10493,7 @@ c_parser_omp_clause_final (c_parser *parser, tree list) return list; } -/* OpenMP 2.5: +/* OpenACC, OpenMP 2.5: if ( expression ) */ static tree @@ -10261,6 +10561,51 @@ c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list) return c; } +/* OpenACC: + num_gangs ( expression ) */ + +static tree +c_parser_omp_clause_num_gangs (c_parser *parser, tree list) +{ + location_t num_gangs_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, + "%<num_gangs%> value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_GANGS, "num_gangs"); + + c = build_omp_clause (num_gangs_loc, OMP_CLAUSE_NUM_GANGS); + OMP_CLAUSE_NUM_GANGS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + /* OpenMP 2.5: num_threads ( expression ) */ @@ -10306,6 +10651,100 @@ c_parser_omp_clause_num_threads (c_parser *parser, tree list) return list; } +/* OpenACC: + num_workers ( expression ) */ + +static tree +c_parser_omp_clause_num_workers (c_parser *parser, tree list) +{ + location_t num_workers_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, + "%<num_workers%> value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_WORKERS, "num_workers"); + + c = build_omp_clause (num_workers_loc, OMP_CLAUSE_NUM_WORKERS); + OMP_CLAUSE_NUM_WORKERS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + +/* OpenACC: + async [( int-expr )] */ + +static tree +c_parser_oacc_clause_async (c_parser *parser, tree list) +{ + tree c, t; + location_t loc = c_parser_peek_token (parser)->location; + + t = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); + + if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) + { + c_parser_consume_token (parser); + + t = c_parser_expression (parser).value; + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + c_parser_error (parser, "expected integer expression"); + else if (t == error_mark_node + || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>")) + return list; + } + else + t = c_fully_fold (t, false, NULL); + + check_no_duplicate_clause (list, OMP_CLAUSE_ASYNC, "async"); + + c = build_omp_clause (loc, OMP_CLAUSE_ASYNC); + OMP_CLAUSE_ASYNC_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + + return list; +} + +/* OpenACC: + wait ( int-expr-list ) */ + +static tree +c_parser_oacc_clause_wait (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + + if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) + list = c_parser_oacc_wait_list (parser, clause_loc, list); + + return list; +} + /* OpenMP 2.5: ordered */ @@ -10557,6 +10996,51 @@ c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list) return c; } +/* OpenACC: + vector_length ( expression ) */ + +static tree +c_parser_omp_clause_vector_length (c_parser *parser, tree list) +{ + location_t vector_length_loc = c_parser_peek_token (parser)->location; + if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + tree c, t = c_parser_expression (parser).value; + mark_exp_read (t); + t = c_fully_fold (t, false, NULL); + + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + + /* Attempt to statically determine when the number isn't positive. */ + c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t, + build_int_cst (TREE_TYPE (t), 0)); + if (CAN_HAVE_LOCATION_P (c)) + SET_EXPR_LOCATION (c, expr_loc); + if (c == boolean_true_node) + { + warning_at (expr_loc, 0, + "%<vector_length%> value must be positive"); + t = integer_one_node; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_VECTOR_LENGTH, "vector_length"); + + c = build_omp_clause (vector_length_loc, OMP_CLAUSE_VECTOR_LENGTH); + OMP_CLAUSE_VECTOR_LENGTH_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + /* OpenMP 4.0: inbranch notinbranch */ @@ -10898,7 +11382,7 @@ static tree c_parser_omp_clause_map (c_parser *parser, tree list) { location_t clause_loc = c_parser_peek_token (parser)->location; - enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + enum gomp_map_kind kind = GOMP_MAP_TOFROM; tree nl, c; if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) @@ -10909,13 +11393,13 @@ c_parser_omp_clause_map (c_parser *parser, tree list) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (strcmp ("alloc", p) == 0) - kind = OMP_CLAUSE_MAP_ALLOC; + kind = GOMP_MAP_ALLOC; else if (strcmp ("to", p) == 0) - kind = OMP_CLAUSE_MAP_TO; + kind = GOMP_MAP_TO; else if (strcmp ("from", p) == 0) - kind = OMP_CLAUSE_MAP_FROM; + kind = GOMP_MAP_FROM; else if (strcmp ("tofrom", p) == 0) - kind = OMP_CLAUSE_MAP_TOFROM; + kind = GOMP_MAP_TOFROM; else { c_parser_error (parser, "invalid map kind"); @@ -10930,7 +11414,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list) nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_MAP_KIND (c) = kind; + OMP_CLAUSE_SET_MAP_KIND (c, kind); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); return nl; @@ -11093,9 +11577,154 @@ c_parser_omp_clause_uniform (c_parser *parser, tree list) return list; } +/* Parse all OpenACC clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found. */ + +static tree +c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, + const char *where, bool finish_p = true) +{ + tree clauses = NULL; + bool first = true; + + while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + const char *c_name; + tree prev = clauses; + + if (!first && c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); + + here = c_parser_peek_token (parser)->location; + c_kind = c_parser_omp_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_OACC_CLAUSE_ASYNC: + clauses = c_parser_oacc_clause_async (parser, clauses); + c_name = "async"; + break; + case PRAGMA_OACC_CLAUSE_COLLAPSE: + clauses = c_parser_omp_clause_collapse (parser, clauses); + c_name = "collapse"; + break; + case PRAGMA_OACC_CLAUSE_COPY: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copy"; + break; + case PRAGMA_OACC_CLAUSE_COPYIN: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copyin"; + break; + case PRAGMA_OACC_CLAUSE_COPYOUT: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copyout"; + break; + case PRAGMA_OACC_CLAUSE_CREATE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "create"; + break; + case PRAGMA_OACC_CLAUSE_DELETE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "delete"; + break; + case PRAGMA_OACC_CLAUSE_DEVICE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "device"; + break; + case PRAGMA_OACC_CLAUSE_DEVICEPTR: + clauses = c_parser_oacc_data_clause_deviceptr (parser, clauses); + c_name = "deviceptr"; + break; + case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE: + clauses = c_parser_omp_clause_firstprivate (parser, clauses); + c_name = "firstprivate"; + break; + case PRAGMA_OACC_CLAUSE_HOST: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "host"; + break; + case PRAGMA_OACC_CLAUSE_IF: + clauses = c_parser_omp_clause_if (parser, clauses); + c_name = "if"; + break; + case PRAGMA_OACC_CLAUSE_NUM_GANGS: + clauses = c_parser_omp_clause_num_gangs (parser, clauses); + c_name = "num_gangs"; + break; + case PRAGMA_OACC_CLAUSE_NUM_WORKERS: + clauses = c_parser_omp_clause_num_workers (parser, clauses); + c_name = "num_workers"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_copy"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_copyin"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_copyout"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_create"; + break; + case PRAGMA_OACC_CLAUSE_PRIVATE: + clauses = c_parser_omp_clause_private (parser, clauses); + c_name = "private"; + break; + case PRAGMA_OACC_CLAUSE_REDUCTION: + clauses = c_parser_omp_clause_reduction (parser, clauses); + c_name = "reduction"; + break; + case PRAGMA_OACC_CLAUSE_SELF: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "self"; + break; + case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH: + clauses = c_parser_omp_clause_vector_length (parser, clauses); + c_name = "vector_length"; + break; + case PRAGMA_OACC_CLAUSE_WAIT: + clauses = c_parser_oacc_clause_wait (parser, clauses); + c_name = "wait"; + break; + default: + c_parser_error (parser, "expected %<#pragma acc%> clause"); + goto saw_error; + } + + first = false; + + if (((mask >> c_kind) & 1) == 0 && !parser->error) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error_at (here, "%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + c_parser_skip_to_pragma_eol (parser); + + if (finish_p) + return c_finish_omp_clauses (clauses); + + return clauses; +} + /* Parse all OpenMP clauses. The set clauses allowed by the directive - is a bitmask in MASK. Return the list of clauses found; the result - of clause default goes in *pdefault. */ + is a bitmask in MASK. Return the list of clauses found. */ static tree c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, @@ -11323,7 +11952,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, return clauses; } -/* OpenMP 2.5: +/* OpenACC 2.0, OpenMP 2.5: structured-block: statement @@ -11339,6 +11968,351 @@ c_parser_omp_structured_block (c_parser *parser) return pop_stmt_list (stmt); } +/* OpenACC 2.0: + # pragma acc cache (variable-list) new-line + + LOC is the location of the #pragma token. +*/ + +static tree +c_parser_oacc_cache (location_t loc, c_parser *parser) +{ + tree stmt, clauses; + + clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL); + clauses = c_finish_omp_clauses (clauses); + + c_parser_skip_to_pragma_eol (parser); + + stmt = make_node (OACC_CACHE); + TREE_TYPE (stmt) = void_type_node; + OACC_CACHE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc data oacc-data-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OACC_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) ) + +static tree +c_parser_oacc_data (location_t loc, c_parser *parser) +{ + tree stmt, clauses, block; + + clauses = c_parser_oacc_all_clauses (parser, OACC_DATA_CLAUSE_MASK, + "#pragma acc data"); + + block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser)); + + stmt = c_finish_oacc_data (loc, clauses, block); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc kernels oacc-kernels-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OACC_KERNELS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static tree +c_parser_oacc_kernels (location_t loc, c_parser *parser, char *p_name) +{ + tree stmt, clauses = NULL_TREE, block; + + strcat (p_name, " kernels"); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "loop") == 0) + { + c_parser_consume_token (parser); + block = c_begin_omp_parallel (); + c_parser_oacc_loop (loc, parser, p_name); + stmt = c_finish_oacc_kernels (loc, clauses, block); + OACC_KERNELS_COMBINED (stmt) = 1; + return stmt; + } + } + + clauses = c_parser_oacc_all_clauses (parser, OACC_KERNELS_CLAUSE_MASK, + p_name); + + block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser)); + + stmt = c_finish_oacc_kernels (loc, clauses, block); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc enter data oacc-enter-data-clause[optseq] new-line + + or + + # pragma acc exit data oacc-exit-data-clause[optseq] new-line + + + LOC is the location of the #pragma token. +*/ + +#define OACC_ENTER_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +#define OACC_EXIT_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static void +c_parser_oacc_enter_exit_data (c_parser *parser, bool enter) +{ + location_t loc = c_parser_peek_token (parser)->location; + tree clauses, stmt; + + c_parser_consume_pragma (parser); + + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + c_parser_error (parser, enter + ? "expected %<data%> in %<#pragma acc enter data%>" + : "expected %<data%> in %<#pragma acc exit data%>"); + c_parser_skip_to_pragma_eol (parser); + return; + } + + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "data") != 0) + { + c_parser_error (parser, "invalid pragma"); + c_parser_skip_to_pragma_eol (parser); + return; + } + + c_parser_consume_token (parser); + + if (enter) + clauses = c_parser_oacc_all_clauses (parser, OACC_ENTER_DATA_CLAUSE_MASK, + "#pragma acc enter data"); + else + clauses = c_parser_oacc_all_clauses (parser, OACC_EXIT_DATA_CLAUSE_MASK, + "#pragma acc exit data"); + + if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) + { + error_at (loc, enter + ? "%<#pragma acc enter data%> has no data movement clause" + : "%<#pragma acc exit data%> has no data movement clause"); + return; + } + + stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA);; + TREE_TYPE (stmt) = void_type_node; + if (enter) + OACC_ENTER_DATA_CLAUSES (stmt) = clauses; + else + OACC_EXIT_DATA_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); +} + + +/* OpenACC 2.0: + + # pragma acc loop oacc-loop-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OACC_LOOP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) ) + +static tree +c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name) +{ + tree stmt, clauses, block; + + strcat (p_name, " loop"); + + clauses = c_parser_oacc_all_clauses (parser, OACC_LOOP_CLAUSE_MASK, p_name); + + block = c_begin_compound_stmt (true); + stmt = c_parser_omp_for_loop (loc, parser, OACC_LOOP, clauses, NULL); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc parallel oacc-parallel-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OACC_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static tree +c_parser_oacc_parallel (location_t loc, c_parser *parser, char *p_name) +{ + tree stmt, clauses = NULL_TREE, block; + + strcat (p_name, " parallel"); + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "loop") == 0) + { + c_parser_consume_token (parser); + block = c_begin_omp_parallel (); + c_parser_oacc_loop (loc, parser, p_name); + stmt = c_finish_oacc_parallel (loc, clauses, block); + OACC_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + } + + clauses = c_parser_oacc_all_clauses (parser, OACC_PARALLEL_CLAUSE_MASK, + p_name); + + block = c_begin_omp_parallel (); + add_stmt (c_parser_omp_structured_block (parser)); + + stmt = c_finish_oacc_parallel (loc, clauses, block); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc update oacc-update-clause[optseq] new-line +*/ + +#define OACC_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static void +c_parser_oacc_update (c_parser *parser) +{ + location_t loc = c_parser_peek_token (parser)->location; + + c_parser_consume_pragma (parser); + + tree clauses = c_parser_oacc_all_clauses (parser, OACC_UPDATE_CLAUSE_MASK, + "#pragma acc update"); + if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) + { + error_at (loc, + "%<#pragma acc update%> must contain at least one " + "%<device%> or %<host/self%> clause"); + return; + } + + if (parser->error) + return; + + tree stmt = make_node (OACC_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OACC_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); +} + +/* OpenACC 2.0: + # pragma acc wait [(intseq)] oacc-wait-clause[optseq] new-line + + LOC is the location of the #pragma token. +*/ + +#define OACC_WAIT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) ) + +static tree +c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name) +{ + tree clauses, list = NULL_TREE, stmt = NULL_TREE; + + if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN) + list = c_parser_oacc_wait_list (parser, loc, list); + + strcpy (p_name, " wait"); + clauses = c_parser_oacc_all_clauses (parser, OACC_WAIT_CLAUSE_MASK, p_name); + stmt = c_finish_oacc_wait (loc, list, clauses); + + return stmt; +} + /* OpenMP 2.5: # pragma omp atomic new-line expression-stmt @@ -11815,10 +12789,11 @@ c_parser_omp_flush (c_parser *parser) c_finish_omp_flush (loc); } -/* Parse the restricted form of the for statement allowed by OpenMP. +/* Parse the restricted form of loop statements allowed by OpenACC and OpenMP. The real trick here is to determine the loop control variable early so that we can push a new decl if necessary to make it private. - LOC is the location of the OMP in "#pragma omp". */ + LOC is the location of the "acc" or "omp" in "#pragma acc" or "#pragma omp", + respectively. */ static tree c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, @@ -13660,6 +14635,29 @@ c_parser_omp_construct (c_parser *parser) switch (p_kind) { + case PRAGMA_OACC_CACHE: + strcpy (p_name, "#pragma acc"); + stmt = c_parser_oacc_cache (loc, parser); + break; + case PRAGMA_OACC_DATA: + stmt = c_parser_oacc_data (loc, parser); + break; + case PRAGMA_OACC_KERNELS: + strcpy (p_name, "#pragma acc"); + stmt = c_parser_oacc_kernels (loc, parser, p_name); + break; + case PRAGMA_OACC_LOOP: + strcpy (p_name, "#pragma acc"); + stmt = c_parser_oacc_loop (loc, parser, p_name); + break; + case PRAGMA_OACC_PARALLEL: + strcpy (p_name, "#pragma acc"); + stmt = c_parser_oacc_parallel (loc, parser, p_name); + break; + case PRAGMA_OACC_WAIT: + strcpy (p_name, "#pragma wait"); + stmt = c_parser_oacc_wait (loc, parser, p_name); + break; case PRAGMA_OMP_ATOMIC: c_parser_omp_atomic (loc, parser); return; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 01becd7..c879bc7 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -640,6 +640,9 @@ extern tree c_finish_bc_stmt (location_t, tree *, bool); extern tree c_finish_goto_label (location_t, tree); extern tree c_finish_goto_ptr (location_t, tree); extern tree c_expr_to_decl (tree, bool *, bool *); +extern tree c_finish_oacc_parallel (location_t, tree, tree); +extern tree c_finish_oacc_kernels (location_t, tree, tree); +extern tree c_finish_oacc_data (location_t, tree, tree); extern tree c_begin_omp_parallel (void); extern tree c_finish_omp_parallel (location_t, tree, tree); extern tree c_begin_omp_task (void); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index a851c8d..f39dfdd 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3. If not see #include "c-family/c-ubsan.h" #include "cilk.h" #include "wide-int.h" +#include "gomp-constants.h" /* Possible cases of implicit bad conversions. Used to select diagnostic messages in convert_for_assignment. */ @@ -11352,6 +11353,63 @@ c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED, bool *se) return expr; } +/* Generate OACC_PARALLEL, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_PARALLEL. */ + +tree +c_finish_oacc_parallel (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OACC_PARALLEL); + TREE_TYPE (stmt) = void_type_node; + OACC_PARALLEL_CLAUSES (stmt) = clauses; + OACC_PARALLEL_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Generate OACC_KERNELS, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_KERNELS. */ + +tree +c_finish_oacc_kernels (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OACC_KERNELS); + TREE_TYPE (stmt) = void_type_node; + OACC_KERNELS_CLAUSES (stmt) = clauses; + OACC_KERNELS_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + +/* Generate OACC_DATA, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_DATA. */ + +tree +c_finish_oacc_data (location_t loc, tree clauses, tree block) +{ + tree stmt; + + block = c_end_compound_stmt (loc, block, true); + + stmt = make_node (OACC_DATA); + TREE_TYPE (stmt) = void_type_node; + OACC_DATA_CLAUSES (stmt) = clauses; + OACC_DATA_BODY (stmt) = block; + SET_EXPR_LOCATION (stmt, loc); + + return add_stmt (stmt); +} + /* Like c_begin_compound_stmt, except force the retention of the BLOCK. */ tree @@ -11883,8 +11941,9 @@ handle_omp_array_sections (tree c) OMP_CLAUSE_SIZE (c) = size; if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) return false; + gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); if (!c_mark_addressable (t)) return false; OMP_CLAUSE_DECL (c2) = t; @@ -11946,7 +12005,7 @@ c_find_omp_placeholder_r (tree *tp, int *, void *data) return NULL_TREE; } -/* For all elements of CLAUSES, validate them vs OpenMP constraints. +/* For all elements of CLAUSES, validate them against their constraints. Remove any elements from the list that are invalid. */ tree @@ -12268,6 +12327,7 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_MAP: case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + case OMP_CLAUSE__CACHE_: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST) { @@ -12306,7 +12366,9 @@ c_finish_omp_clauses (tree clauses) else if (!c_mark_addressable (t)) remove = true; else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER) + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FORCE_DEVICEPTR))) && !lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) { error_at (OMP_CLAUSE_LOCATION (c), @@ -12375,6 +12437,16 @@ c_finish_omp_clauses (tree clauses) case OMP_CLAUSE_TASKGROUP: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE__CILK_FOR_COUNT_: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_SEQ: + case OMP_CLAUSE_GANG: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: pc = &OMP_CLAUSE_CHAIN (c); continue; diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 1a06cad..b28966e 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -512,7 +512,7 @@ cgraph_node::create (tree decl) node->decl = decl; - if (flag_openmp + if ((flag_openacc || flag_openmp) && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))) { node->offloadable = 1; diff --git a/gcc/config.gcc b/gcc/config.gcc index 0dfc08f..bf67beb 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -2233,6 +2233,7 @@ nios2-*-*) nvptx-*) tm_file="${tm_file} newlib-stdint.h" tmake_file="nvptx/t-nvptx" + tm_file="${tm_file} nvptx/offload.h" ;; pdp11-*-*) tm_file="${tm_file} newlib-stdint.h" @@ -2965,6 +2966,7 @@ esac case ${target} in *-intelmic-* | *-intelmicemul-*) tmake_file="${tmake_file} i386/t-intelmic" + tm_file="${tm_file} i386/intelmic-offload.h" ;; esac diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h index b0dd66f..3be5c93 100644 --- a/gcc/config/arc/arc.h +++ b/gcc/config/arc/arc.h @@ -173,7 +173,7 @@ along with GCC; see the file COPYING3. If not see %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\ %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\ %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\ - %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\ + %{fopenacc|fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\ %(mflib)\ %{fprofile-arcs|fprofile-generate|coverage:-lgcov}\ %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\ diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index 4bae095..b61dbb5 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -177,7 +177,7 @@ extern GTY(()) int darwin_ms_struct; %{o*}%{!o:-o a.out} \ %{!nostdlib:%{!nostartfiles:%S}} \ %{L*} %(link_libgcc) %o %{fprofile-arcs|fprofile-generate*|coverage:-lgcov} \ - %{fopenmp|ftree-parallelize-loops=*: \ + %{fopenacc|fopenmp|ftree-parallelize-loops=*: \ %{static|static-libgcc|static-libstdc++|static-libgfortran: libgomp.a%s; : -lgomp } } \ %{fgnu-tm: \ %{static|static-libgcc|static-libstdc++|static-libgfortran: libitm.a%s; : -litm } } \ diff --git a/gcc/config/i386/intelmic-mkoffload.c b/gcc/config/i386/intelmic-mkoffload.c index 050f2e6..edc3f92 100644 --- a/gcc/config/i386/intelmic-mkoffload.c +++ b/gcc/config/i386/intelmic-mkoffload.c @@ -22,13 +22,13 @@ #include "config.h" #include <libgen.h> +#include "libgomp-plugin.h" #include "system.h" #include "coretypes.h" #include "obstack.h" #include "intl.h" #include "diagnostic.h" #include "collect-utils.h" -#include <libgomp_target.h> const char tool_name[] = "intelmic mkoffload"; diff --git a/gcc/config/i386/intelmic-offload.h b/gcc/config/i386/intelmic-offload.h new file mode 100644 index 0000000..4fb4b65 --- /dev/null +++ b/gcc/config/i386/intelmic-offload.h @@ -0,0 +1,35 @@ +/* Support for Intel MIC offloading. + + Copyright (C) 2014-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef INTELMIC_OFFLOAD_H +#define INTELMIC_OFFLOAD_H + +/* Support for OpenACC acc_on_device. */ + +#include "gomp-constants.h" + +#define ACCEL_COMPILER_acc_device GOMP_DEVICE_INTEL_MIC + +#endif diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h index a7e66cd..d7b92e8 100644 --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -199,7 +199,7 @@ do { \ /* mingw32 uses the -mthreads option to enable thread support. */ #undef GOMP_SELF_SPECS -#define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: " \ +#define GOMP_SELF_SPECS "%{fopenacc|fopenmp|ftree-parallelize-loops=*: " \ "-mthreads -pthread}" #undef GTM_SELF_SPECS #define GTM_SELF_SPECS "%{fgnu-tm:-mthreads -pthread}" diff --git a/gcc/config/ia64/hpux.h b/gcc/config/ia64/hpux.h index 0cb2fc2..a497e44 100644 --- a/gcc/config/ia64/hpux.h +++ b/gcc/config/ia64/hpux.h @@ -92,7 +92,7 @@ do { \ #undef LIB_SPEC #define LIB_SPEC \ "%{!shared: \ - %{mt|pthread:%{fopenmp|ftree-parallelize-loops=*:-lrt} -lpthread} \ + %{mt|pthread:%{fopenacc|fopenmp|ftree-parallelize-loops=*:-lrt} -lpthread} \ %{p:%{!mlp64:-L/usr/lib/hpux32/libp} \ %{mlp64:-L/usr/lib/hpux64/libp} -lprof} \ %{pg:%{!mlp64:-L/usr/lib/hpux32/libp} \ diff --git a/gcc/config/nvptx/offload.h b/gcc/config/nvptx/offload.h new file mode 100644 index 0000000..02c5e8b --- /dev/null +++ b/gcc/config/nvptx/offload.h @@ -0,0 +1,35 @@ +/* Support for Nvidia PTX offloading. + + Copyright (C) 2014-2015 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_NVPTX_OFFLOAD_H +#define GCC_NVPTX_OFFLOAD_H + +/* Support for OpenACC acc_on_device. */ + +#include "gomp-constants.h" + +#define ACCEL_COMPILER_acc_device GOMP_TARGET_NVIDIA_PTX + +#endif diff --git a/gcc/config/pa/pa-hpux11.h b/gcc/config/pa/pa-hpux11.h index 0e0c33e..40d49a0 100644 --- a/gcc/config/pa/pa-hpux11.h +++ b/gcc/config/pa/pa-hpux11.h @@ -122,8 +122,8 @@ along with GCC; see the file COPYING3. If not see #undef LIB_SPEC #define LIB_SPEC \ "%{!shared:\ - %{fopenmp|ftree-parallelize-loops=*:%{static:-a archive_shared} -lrt\ - %{static:-a archive}}\ + %{fopenacc|fopenmp|ftree-parallelize-loops=*:\ + %{static:-a archive_shared} -lrt %{static:-a archive}}\ %{mt|pthread:-lpthread} -lc\ %{static:%{!nolibdld:-a archive_shared -ldld -a archive -lc}\ %{!mt:%{!pthread:-a shared -lc -a archive}}}}\ diff --git a/gcc/config/pa/pa64-hpux.h b/gcc/config/pa/pa64-hpux.h index 11630b7..0af5c17 100644 --- a/gcc/config/pa/pa64-hpux.h +++ b/gcc/config/pa/pa64-hpux.h @@ -58,22 +58,22 @@ along with GCC; see the file COPYING3. If not see #if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GNU_LD) #define LIB_SPEC \ "%{!shared:\ - %{!p:%{!pg:%{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\ - %{static:-a archive}}\ + %{!p:%{!pg:%{fopenacc|fopenmp|ftree-parallelize-loops=*:\ + %{static:-a shared} -lrt %{static:-a archive}}\ %{mt|pthread:-lpthread} -lc\ %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\ %{!mt:%{!pthread:-a shared -lc -a archive}}}}}\ %{p:%{!pg:%{static:%{!mhp-ld:-a shared}%{mhp-ld:-a archive_shared}}\ -lprof %{static:-a archive}\ - %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\ - %{static:-a archive}}\ + %{fopenacc|fopenmp|ftree-parallelize-loops=*:\ + %{static:-a shared} -lrt %{static:-a archive}}\ %{mt|pthread:-lpthread} -lc\ %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\ %{!mt:%{!pthread:-a shared -lc -a archive}}}}}\ %{pg:%{static:%{!mhp-ld:-a shared}%{mhp-ld:-a archive_shared}}\ -lgprof %{static:-a archive}\ - %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\ - %{static:-a archive}}\ + %{fopenacc|fopenmp|ftree-parallelize-loops=*:\ + %{static:-a shared} -lrt %{static:-a archive}}\ %{mt|pthread:-lpthread} -lc\ %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\ %{!mt:%{!pthread:-a shared -lc -a archive}}}}}\ @@ -81,22 +81,22 @@ along with GCC; see the file COPYING3. If not see #else #define LIB_SPEC \ "%{!shared:\ - %{!p:%{!pg:%{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\ - %{static:-a archive}}\ + %{!p:%{!pg:%{fopenacc|fopenmp|ftree-parallelize-loops=*:\ + %{static:-a shared} -lrt %{static:-a archive}}\ %{mt|pthread:-lpthread} -lc\ %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\ %{!mt:%{!pthread:-a shared -lc -a archive}}}}}\ %{p:%{!pg:%{static:%{mgnu-ld:-a shared}%{!mgnu-ld:-a archive_shared}}\ -lprof %{static:-a archive}\ - %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\ - %{static:-a archive}}\ + %{fopenacc|fopenmp|ftree-parallelize-loops=*:\ + %{static:-a shared} -lrt %{static:-a archive}}\ %{mt|pthread:-lpthread} -lc\ %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\ %{!mt:%{!pthread:-a shared -lc -a archive}}}}}\ %{pg:%{static:%{mgnu-ld:-a shared}%{!mgnu-ld:-a archive_shared}}\ -lgprof %{static:-a archive}\ - %{fopenmp|ftree-parallelize-loops=*:%{static:-a shared} -lrt\ - %{static:-a archive}}\ + %{fopenacc|fopenmp|ftree-parallelize-loops=*:\ + %{static:-a shared} -lrt %{static:-a archive}}\ %{mt|pthread:-lpthread} -lc\ %{static:%{!nolibdld:-a shared -ldld -a archive -lc}\ %{!mt:%{!pthread:-a shared -lc -a archive}}}}}\ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 02b4fac..543f4d9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,48 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + James Norris <jnorris@codesourcery.com> + Cesar Philippidis <cesar@codesourcery.com> + Ilmir Usmanov <i.usmanov@samsung.com> + Jakub Jelinek <jakub@redhat.com> + + * parser.c: Include "gomp-constants.h". + (cp_parser_omp_clause_map): Use enum gomp_map_kind instead of enum + omp_clause_map_kind. Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. + Use OMP_CLAUSE_SET_MAP_KIND. + (cp_parser_omp_construct, cp_parser_pragma): Handle + PRAGMA_OACC_CACHE, PRAGMA_OACC_DATA, PRAGMA_OACC_ENTER_DATA, + PRAGMA_OACC_EXIT_DATA, PRAGMA_OACC_KERNELS, PRAGMA_OACC_PARALLEL, + PRAGMA_OACC_LOOP, PRAGMA_OACC_UPDATE, PRAGMA_OACC_WAIT. + (cp_parser_omp_clause_name): Handle "async", "copy", "copyout", + "create", "delete", "deviceptr", "host", "num_gangs", + "num_workers", "present", "present_or_copy", "pcopy", + "present_or_copyin", "pcopyin", "present_or_copyout", "pcopyout", + "present_or_create", "pcreate", "vector_length", "wait". + (OACC_DATA_CLAUSE_MASK, OACC_ENTER_DATA_CLAUSE_MASK) + (OACC_EXIT_DATA_CLAUSE_MASK, OACC_KERNELS_CLAUSE_MASK) + (OACC_LOOP_CLAUSE_MASK, OACC_PARALLEL_CLAUSE_MASK) + (OACC_UPDATE_CLAUSE_MASK, OACC_WAIT_CLAUSE_MASK): New macros. + (cp_parser_omp_var_list_no_open): Handle OMP_CLAUSE__CACHE_. + (cp_parser_oacc_data_clause, cp_parser_oacc_data_clause_deviceptr) + (cp_parser_oacc_clause_vector_length, cp_parser_oacc_wait_list) + (cp_parser_oacc_clause_wait, cp_parser_omp_clause_num_gangs) + (cp_parser_omp_clause_num_workers, cp_parser_oacc_clause_async) + (cp_parser_oacc_all_clauses, cp_parser_oacc_cache) + (cp_parser_oacc_data, cp_parser_oacc_enter_exit_data) + (cp_parser_oacc_kernels, cp_parser_oacc_loop) + (cp_parser_oacc_parallel, cp_parser_oacc_update) + (cp_parser_oacc_wait): New functions. + * cp-tree.h (finish_oacc_data, finish_oacc_kernels) + (finish_oacc_parallel): New prototypes. + * semantics.c: Include "gomp-constants.h". + (handle_omp_array_sections): Handle GOMP_MAP_FORCE_DEVICEPTR. Use + GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. Use + OMP_CLAUSE_SET_MAP_KIND. + (finish_omp_clauses): Handle OMP_CLAUSE_ASYNC, + OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_WAIT, OMP_CLAUSE__CACHE_. + Use GOMP_MAP_* instead of OMP_CLAUSE_MAP_*. + (finish_oacc_data, finish_oacc_kernels, finish_oacc_parallel): New + functions. + 2015-01-14 Paolo Carlini <paolo.carlini@oracle.com> PR c++/58671 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 77f2b5b..10c63fd 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5990,6 +5990,9 @@ extern tree finish_omp_clauses (tree); extern void finish_omp_threadprivate (tree); extern tree begin_omp_structured_block (void); extern tree finish_omp_structured_block (tree); +extern tree finish_oacc_data (tree, tree); +extern tree finish_oacc_kernels (tree, tree); +extern tree finish_oacc_parallel (tree, tree); extern tree begin_omp_parallel (void); extern tree finish_omp_parallel (tree, tree); extern tree begin_omp_task (void); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 3290dfa..bfa3d81 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "parser.h" #include "type-utils.h" #include "omp-low.h" +#include "gomp-constants.h" /* The lexer. */ @@ -27542,6 +27543,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_IF; else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DEFAULT)) result = PRAGMA_OMP_CLAUSE_DEFAULT; + else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DELETE)) + result = PRAGMA_OACC_CLAUSE_DELETE; else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_PRIVATE)) result = PRAGMA_OMP_CLAUSE_PRIVATE; else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) @@ -27556,20 +27559,30 @@ cp_parser_omp_clause_name (cp_parser *parser) case 'a': if (!strcmp ("aligned", p)) result = PRAGMA_OMP_CLAUSE_ALIGNED; + else if (!strcmp ("async", p)) + result = PRAGMA_OACC_CLAUSE_ASYNC; break; case 'c': if (!strcmp ("collapse", p)) result = PRAGMA_OMP_CLAUSE_COLLAPSE; + else if (!strcmp ("copy", p)) + result = PRAGMA_OACC_CLAUSE_COPY; else if (!strcmp ("copyin", p)) result = PRAGMA_OMP_CLAUSE_COPYIN; + else if (!strcmp ("copyout", p)) + result = PRAGMA_OACC_CLAUSE_COPYOUT; else if (!strcmp ("copyprivate", p)) result = PRAGMA_OMP_CLAUSE_COPYPRIVATE; + else if (!strcmp ("create", p)) + result = PRAGMA_OACC_CLAUSE_CREATE; break; case 'd': if (!strcmp ("depend", p)) result = PRAGMA_OMP_CLAUSE_DEPEND; else if (!strcmp ("device", p)) result = PRAGMA_OMP_CLAUSE_DEVICE; + else if (!strcmp ("deviceptr", p)) + result = PRAGMA_OACC_CLAUSE_DEVICEPTR; else if (!strcmp ("dist_schedule", p)) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; @@ -27581,6 +27594,10 @@ cp_parser_omp_clause_name (cp_parser *parser) else if (!strcmp ("from", p)) result = PRAGMA_OMP_CLAUSE_FROM; break; + case 'h': + if (!strcmp ("host", p)) + result = PRAGMA_OACC_CLAUSE_HOST; + break; case 'i': if (!strcmp ("inbranch", p)) result = PRAGMA_OMP_CLAUSE_INBRANCH; @@ -27606,10 +27623,14 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_NOWAIT; else if (flag_cilkplus && !strcmp ("nomask", p)) result = PRAGMA_CILK_CLAUSE_NOMASK; + else if (!strcmp ("num_gangs", p)) + result = PRAGMA_OACC_CLAUSE_NUM_GANGS; else if (!strcmp ("num_teams", p)) result = PRAGMA_OMP_CLAUSE_NUM_TEAMS; else if (!strcmp ("num_threads", p)) result = PRAGMA_OMP_CLAUSE_NUM_THREADS; + else if (!strcmp ("num_workers", p)) + result = PRAGMA_OACC_CLAUSE_NUM_WORKERS; break; case 'o': if (!strcmp ("ordered", p)) @@ -27618,6 +27639,20 @@ cp_parser_omp_clause_name (cp_parser *parser) case 'p': if (!strcmp ("parallel", p)) result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("present", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT; + else if (!strcmp ("present_or_copy", p) + || !strcmp ("pcopy", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY; + else if (!strcmp ("present_or_copyin", p) + || !strcmp ("pcopyin", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN; + else if (!strcmp ("present_or_copyout", p) + || !strcmp ("pcopyout", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT; + else if (!strcmp ("present_or_create", p) + || !strcmp ("pcreate", p)) + result = PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE; else if (!strcmp ("proc_bind", p)) result = PRAGMA_OMP_CLAUSE_PROC_BIND; break; @@ -27632,6 +27667,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_SCHEDULE; else if (!strcmp ("sections", p)) result = PRAGMA_OMP_CLAUSE_SECTIONS; + else if (!strcmp ("self", p)) + result = PRAGMA_OACC_CLAUSE_SELF; else if (!strcmp ("shared", p)) result = PRAGMA_OMP_CLAUSE_SHARED; else if (!strcmp ("simdlen", p)) @@ -27652,9 +27689,15 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_UNTIED; break; case 'v': - if (flag_cilkplus && !strcmp ("vectorlength", p)) + if (!strcmp ("vector_length", p)) + result = PRAGMA_OACC_CLAUSE_VECTOR_LENGTH; + else if (flag_cilkplus && !strcmp ("vectorlength", p)) result = PRAGMA_CILK_CLAUSE_VECTORLENGTH; break; + case 'w': + if (!strcmp ("wait", p)) + result = PRAGMA_OACC_CLAUSE_WAIT; + break; } } @@ -27730,6 +27773,14 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, { switch (kind) { + case OMP_CLAUSE__CACHE_: + if (cp_lexer_peek_token (parser->lexer)->type != CPP_OPEN_SQUARE) + { + error_at (token->location, "expected %<[%>"); + decl = error_mark_node; + break; + } + /* FALL THROUGH. */ case OMP_CLAUSE_MAP: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: @@ -27760,6 +27811,26 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) goto skip_comma; + + if (kind == OMP_CLAUSE__CACHE_) + { + if (TREE_CODE (low_bound) != INTEGER_CST + && !TREE_READONLY (low_bound)) + { + error_at (token->location, + "%qD is not a constant", low_bound); + decl = error_mark_node; + } + + if (TREE_CODE (length) != INTEGER_CST + && !TREE_READONLY (length)) + { + error_at (token->location, + "%qD is not a constant", length); + decl = error_mark_node; + } + } + decl = tree_cons (low_bound, length, decl); } break; @@ -27822,6 +27893,222 @@ cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list) return list; } +/* OpenACC 2.0: + copy ( variable-list ) + copyin ( variable-list ) + copyout ( variable-list ) + create ( variable-list ) + delete ( variable-list ) + present ( variable-list ) + present_or_copy ( variable-list ) + pcopy ( variable-list ) + present_or_copyin ( variable-list ) + pcopyin ( variable-list ) + present_or_copyout ( variable-list ) + pcopyout ( variable-list ) + present_or_create ( variable-list ) + pcreate ( variable-list ) */ + +static tree +cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind, + tree list) +{ + enum gomp_map_kind kind; + switch (c_kind) + { + case PRAGMA_OACC_CLAUSE_COPY: + kind = GOMP_MAP_FORCE_TOFROM; + break; + case PRAGMA_OACC_CLAUSE_COPYIN: + kind = GOMP_MAP_FORCE_TO; + break; + case PRAGMA_OACC_CLAUSE_COPYOUT: + kind = GOMP_MAP_FORCE_FROM; + break; + case PRAGMA_OACC_CLAUSE_CREATE: + kind = GOMP_MAP_FORCE_ALLOC; + break; + case PRAGMA_OACC_CLAUSE_DELETE: + kind = GOMP_MAP_FORCE_DEALLOC; + break; + case PRAGMA_OACC_CLAUSE_DEVICE: + kind = GOMP_MAP_FORCE_TO; + break; + case PRAGMA_OACC_CLAUSE_HOST: + case PRAGMA_OACC_CLAUSE_SELF: + kind = GOMP_MAP_FORCE_FROM; + break; + case PRAGMA_OACC_CLAUSE_PRESENT: + kind = GOMP_MAP_FORCE_PRESENT; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY: + kind = GOMP_MAP_TOFROM; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN: + kind = GOMP_MAP_TO; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT: + kind = GOMP_MAP_FROM; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE: + kind = GOMP_MAP_ALLOC; + break; + default: + gcc_unreachable (); + } + tree nl, c; + nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list); + + for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) + OMP_CLAUSE_SET_MAP_KIND (c, kind); + + return nl; +} + +/* OpenACC 2.0: + deviceptr ( variable-list ) */ + +static tree +cp_parser_oacc_data_clause_deviceptr (cp_parser *parser, tree list) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree vars, t; + + /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic + cp_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR, + variable-list must only allow for pointer variables. */ + vars = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL); + for (t = vars; t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* FIXME diagnostics: Ideally we should keep individual + locations for all the variables in the var list to make the + following errors more precise. Perhaps + c_parser_omp_var_list_parens should construct a list of + locations to go along with the var list. */ + + if (TREE_CODE (v) != VAR_DECL) + error_at (loc, "%qD is not a variable", v); + else if (TREE_TYPE (v) == error_mark_node) + ; + else if (!POINTER_TYPE_P (TREE_TYPE (v))) + error_at (loc, "%qD is not a pointer variable", v); + + tree u = build_omp_clause (loc, OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (u, GOMP_MAP_FORCE_DEVICEPTR); + OMP_CLAUSE_DECL (u) = v; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + + return list; +} + +/* OpenACC: + vector_length ( expression ) */ + +static tree +cp_parser_oacc_clause_vector_length (cp_parser *parser, tree list) +{ + tree t, c; + location_t location = cp_lexer_peek_token (parser->lexer)->location; + bool error = false; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_condition (parser); + if (t == error_mark_node || !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (location, "expected positive integer expression"); + error = true; + } + + if (error || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + { + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_VECTOR_LENGTH, "vector_length", + location); + + c = build_omp_clause (location, OMP_CLAUSE_VECTOR_LENGTH); + OMP_CLAUSE_VECTOR_LENGTH_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + + return list; +} + +/* OpenACC 2.0 + Parse wait clause or directive parameters. */ + +static tree +cp_parser_oacc_wait_list (cp_parser *parser, location_t clause_loc, tree list) +{ + vec<tree, va_gc> *args; + tree t, args_tree; + + args = cp_parser_parenthesized_expression_list (parser, non_attr, + /*cast_p=*/false, + /*allow_expansion_p=*/true, + /*non_constant_p=*/NULL); + + if (args == NULL || args->length () == 0) + { + cp_parser_error (parser, "expected integer expression before ')'"); + if (args != NULL) + release_tree_vector (args); + return list; + } + + args_tree = build_tree_list_vec (args); + + release_tree_vector (args); + + for (t = args_tree; t; t = TREE_CHAIN (t)) + { + tree targ = TREE_VALUE (t); + + if (targ != error_mark_node) + { + if (!INTEGRAL_TYPE_P (TREE_TYPE (targ))) + error ("%<wait%> expression must be integral"); + else + { + tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT); + + mark_rvalue_use (targ); + OMP_CLAUSE_DECL (c) = targ; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + } + } + + return list; +} + +/* OpenACC: + wait ( int-expr-list ) */ + +static tree +cp_parser_oacc_clause_wait (cp_parser *parser, tree list) +{ + location_t location = cp_lexer_peek_token (parser->lexer)->location; + + if (cp_lexer_peek_token (parser->lexer)->type != CPP_OPEN_PAREN) + return list; + + list = cp_parser_oacc_wait_list (parser, location, list); + + return list; +} + /* OpenMP 3.0: collapse ( constant-expression ) */ @@ -28010,6 +28297,42 @@ cp_parser_omp_clause_nowait (cp_parser * /*parser*/, return c; } +/* OpenACC: + num_gangs ( expression ) */ + +static tree +cp_parser_omp_clause_num_gangs (cp_parser *parser, tree list) +{ + tree t, c; + location_t location = cp_lexer_peek_token (parser->lexer)->location; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_condition (parser); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (location, "expected positive integer expression"); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_GANGS, "num_gangs", location); + + c = build_omp_clause (location, OMP_CLAUSE_NUM_GANGS); + OMP_CLAUSE_NUM_GANGS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + + return list; +} + /* OpenMP 2.5: num_threads ( expression ) */ @@ -28040,6 +28363,43 @@ cp_parser_omp_clause_num_threads (cp_parser *parser, tree list, return c; } +/* OpenACC: + num_workers ( expression ) */ + +static tree +cp_parser_omp_clause_num_workers (cp_parser *parser, tree list) +{ + tree t, c; + location_t location = cp_lexer_peek_token (parser->lexer)->location; + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return list; + + t = cp_parser_condition (parser); + + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (location, "expected positive integer expression"); + return list; + } + + check_no_duplicate_clause (list, OMP_CLAUSE_NUM_WORKERS, "num_gangs", + location); + + c = build_omp_clause (location, OMP_CLAUSE_NUM_WORKERS); + OMP_CLAUSE_NUM_WORKERS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + + return list; +} + /* OpenMP 2.5: ordered */ @@ -28562,7 +28922,7 @@ static tree cp_parser_omp_clause_map (cp_parser *parser, tree list) { tree nlist, c; - enum omp_clause_map_kind kind = OMP_CLAUSE_MAP_TOFROM; + enum gomp_map_kind kind = GOMP_MAP_TOFROM; if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; @@ -28574,13 +28934,13 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) const char *p = IDENTIFIER_POINTER (id); if (strcmp ("alloc", p) == 0) - kind = OMP_CLAUSE_MAP_ALLOC; + kind = GOMP_MAP_ALLOC; else if (strcmp ("to", p) == 0) - kind = OMP_CLAUSE_MAP_TO; + kind = GOMP_MAP_TO; else if (strcmp ("from", p) == 0) - kind = OMP_CLAUSE_MAP_FROM; + kind = GOMP_MAP_FROM; else if (strcmp ("tofrom", p) == 0) - kind = OMP_CLAUSE_MAP_TOFROM; + kind = GOMP_MAP_TOFROM; else { cp_parser_error (parser, "invalid map kind"); @@ -28597,7 +28957,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list) NULL); for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_MAP_KIND (c) = kind; + OMP_CLAUSE_SET_MAP_KIND (c, kind); return nlist; } @@ -28734,6 +29094,178 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, return list; } +/* OpenACC: + async [( int-expr )] */ + +static tree +cp_parser_oacc_clause_async (cp_parser *parser, tree list) +{ + tree c, t; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + t = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL); + + if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) + { + cp_lexer_consume_token (parser->lexer); + + t = cp_parser_expression (parser); + if (t == error_mark_node + || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + } + + check_no_duplicate_clause (list, OMP_CLAUSE_ASYNC, "async", loc); + + c = build_omp_clause (loc, OMP_CLAUSE_ASYNC); + OMP_CLAUSE_ASYNC_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + + return list; +} + +/* Parse all OpenACC clauses. The set clauses allowed by the directive + is a bitmask in MASK. Return the list of clauses found. */ + +static tree +cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, + const char *where, cp_token *pragma_tok, + bool finish_p = true) +{ + tree clauses = NULL; + bool first = true; + + while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)) + { + location_t here; + pragma_omp_clause c_kind; + const char *c_name; + tree prev = clauses; + + if (!first && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + + here = cp_lexer_peek_token (parser->lexer)->location; + c_kind = cp_parser_omp_clause_name (parser); + + switch (c_kind) + { + case PRAGMA_OACC_CLAUSE_ASYNC: + clauses = cp_parser_oacc_clause_async (parser, clauses); + c_name = "async"; + break; + case PRAGMA_OACC_CLAUSE_COLLAPSE: + clauses = cp_parser_omp_clause_collapse (parser, clauses, here); + c_name = "collapse"; + break; + case PRAGMA_OACC_CLAUSE_COPY: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copy"; + break; + case PRAGMA_OACC_CLAUSE_COPYIN: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copyin"; + break; + case PRAGMA_OACC_CLAUSE_COPYOUT: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "copyout"; + break; + case PRAGMA_OACC_CLAUSE_CREATE: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "create"; + break; + case PRAGMA_OACC_CLAUSE_DELETE: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "delete"; + break; + case PRAGMA_OACC_CLAUSE_DEVICE: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "device"; + break; + case PRAGMA_OACC_CLAUSE_DEVICEPTR: + clauses = cp_parser_oacc_data_clause_deviceptr (parser, clauses); + c_name = "deviceptr"; + break; + case PRAGMA_OACC_CLAUSE_HOST: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "host"; + break; + case PRAGMA_OACC_CLAUSE_IF: + clauses = cp_parser_omp_clause_if (parser, clauses, here); + c_name = "if"; + break; + case PRAGMA_OACC_CLAUSE_NUM_GANGS: + clauses = cp_parser_omp_clause_num_gangs (parser, clauses); + c_name = "num_gangs"; + break; + case PRAGMA_OACC_CLAUSE_NUM_WORKERS: + clauses = cp_parser_omp_clause_num_workers (parser, clauses); + c_name = "num_workers"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_copy"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_copyin"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_copyout"; + break; + case PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "present_or_create"; + break; + case PRAGMA_OACC_CLAUSE_REDUCTION: + clauses = cp_parser_omp_clause_reduction (parser, clauses); + c_name = "reduction"; + break; + case PRAGMA_OACC_CLAUSE_SELF: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "self"; + break; + case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH: + clauses = cp_parser_oacc_clause_vector_length (parser, clauses); + c_name = "vector_length"; + break; + case PRAGMA_OACC_CLAUSE_WAIT: + clauses = cp_parser_oacc_clause_wait (parser, clauses); + c_name = "wait"; + break; + default: + cp_parser_error (parser, "expected %<#pragma acc%> clause"); + goto saw_error; + } + + first = false; + + if (((mask >> c_kind) & 1) == 0) + { + /* Remove the invalid clause(s) from the list to avoid + confusing the rest of the compiler. */ + clauses = prev; + error_at (here, "%qs is not valid for %qs", c_name, where); + } + } + + saw_error: + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + + if (finish_p) + return finish_omp_clauses (clauses); + + return clauses; +} + /* Parse all OpenMP clauses. The set clauses allowed by the directive is a bitmask in MASK. Return the list of clauses found; the result of clause default goes in *pdefault. */ @@ -30953,6 +31485,304 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, return true; } +/* OpenACC 2.0: + # pragma acc cache (variable-list) new-line +*/ + +static tree +cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt, clauses; + + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE__CACHE_, NULL_TREE); + clauses = finish_omp_clauses (clauses); + + cp_parser_require_pragma_eol (parser, cp_lexer_peek_token (parser->lexer)); + + stmt = make_node (OACC_CACHE); + TREE_TYPE (stmt) = void_type_node; + OACC_CACHE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + + return stmt; +} + +/* OpenACC 2.0: + # pragma acc data oacc-data-clause[optseq] new-line + structured-block */ + +#define OACC_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE)) + +static tree +cp_parser_oacc_data (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt, clauses, block; + unsigned int save; + + clauses = cp_parser_oacc_all_clauses (parser, OACC_DATA_CLAUSE_MASK, + "#pragma acc data", pragma_tok); + + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_oacc_data (clauses, block); + return stmt; +} + +/* OpenACC 2.0: + # pragma acc enter data oacc-enter-data-clause[optseq] new-line + + or + + # pragma acc exit data oacc-exit-data-clause[optseq] new-line + + LOC is the location of the #pragma token. +*/ + +#define OACC_ENTER_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +#define OACC_EXIT_DATA_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) + +static tree +cp_parser_oacc_enter_exit_data (cp_parser *parser, cp_token *pragma_tok, + bool enter) +{ + tree stmt, clauses; + + if (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA_EOL) + || cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + cp_parser_error (parser, enter + ? "expected %<data%> in %<#pragma acc enter data%>" + : "expected %<data%> in %<#pragma acc exit data%>"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + const char *p = + IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); + if (strcmp (p, "data") != 0) + { + cp_parser_error (parser, "invalid pragma"); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + cp_lexer_consume_token (parser->lexer); + + if (enter) + clauses = cp_parser_oacc_all_clauses (parser, OACC_ENTER_DATA_CLAUSE_MASK, + "#pragma acc enter data", pragma_tok); + else + clauses = cp_parser_oacc_all_clauses (parser, OACC_EXIT_DATA_CLAUSE_MASK, + "#pragma acc exit data", pragma_tok); + + if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) + { + error_at (pragma_tok->location, + "%<#pragma acc enter data%> has no data movement clause"); + return NULL_TREE; + } + + stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA); + TREE_TYPE (stmt) = void_type_node; + if (enter) + OACC_ENTER_DATA_CLAUSES (stmt) = clauses; + else + OACC_EXIT_DATA_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return stmt; +} + +/* OpenACC 2.0: + # pragma acc kernels oacc-kernels-clause[optseq] new-line + structured-block */ + +#define OACC_KERNELS_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT)) + +static tree +cp_parser_oacc_kernels (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt, clauses, block; + unsigned int save; + + clauses = cp_parser_oacc_all_clauses (parser, OACC_KERNELS_CLAUSE_MASK, + "#pragma acc kernels", pragma_tok); + + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_oacc_kernels (clauses, block); + return stmt; +} + +/* OpenACC 2.0: + # pragma acc loop oacc-loop-clause[optseq] new-line + structured-block */ + +#define OACC_LOOP_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION)) + +static tree +cp_parser_oacc_loop (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt, clauses, block; + int save; + + clauses = cp_parser_oacc_all_clauses (parser, OACC_LOOP_CLAUSE_MASK, + "#pragma acc loop", pragma_tok); + + block = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + stmt = cp_parser_omp_for_loop (parser, OACC_LOOP, clauses, NULL); + cp_parser_end_omp_structured_block (parser, save); + add_stmt (finish_omp_structured_block (block)); + return stmt; +} + +/* OpenACC 2.0: + # pragma acc parallel oacc-parallel-clause[optseq] new-line + structured-block */ + +#define OACC_PARALLEL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPY) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYIN) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_COPYOUT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT)) + +static tree +cp_parser_oacc_parallel (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt, clauses, block; + unsigned int save; + + clauses = cp_parser_oacc_all_clauses (parser, OACC_PARALLEL_CLAUSE_MASK, + "#pragma acc parallel", pragma_tok); + + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + cp_parser_statement (parser, NULL_TREE, false, NULL); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_oacc_parallel (clauses, block); + return stmt; +} + +/* OpenACC 2.0: + # pragma acc update oacc-update-clause[optseq] new-line +*/ + +#define OACC_UPDATE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SELF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT)) + +static tree +cp_parser_oacc_update (cp_parser *parser, cp_token *pragma_tok) +{ + tree stmt, clauses; + + clauses = cp_parser_oacc_all_clauses (parser, OACC_UPDATE_CLAUSE_MASK, + "#pragma acc update", pragma_tok); + + if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE) + { + error_at (pragma_tok->location, + "%<#pragma acc update%> must contain at least one " + "%<device%> or %<host/self%> clause"); + return NULL_TREE; + } + + stmt = make_node (OACC_UPDATE); + TREE_TYPE (stmt) = void_type_node; + OACC_UPDATE_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + add_stmt (stmt); + return stmt; +} + +/* OpenACC 2.0: + # pragma acc wait [(intseq)] oacc-wait-clause[optseq] new-line + + LOC is the location of the #pragma token. +*/ + +#define OACC_WAIT_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC)) + +static tree +cp_parser_oacc_wait (cp_parser *parser, cp_token *pragma_tok) +{ + tree clauses, list = NULL_TREE, stmt = NULL_TREE; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + if (cp_lexer_peek_token (parser->lexer)->type == CPP_OPEN_PAREN) + list = cp_parser_oacc_wait_list (parser, loc, list); + + clauses = cp_parser_oacc_all_clauses (parser, OACC_WAIT_CLAUSE_MASK, + "#pragma acc wait", pragma_tok); + + stmt = c_finish_oacc_wait (loc, list, clauses); + + return stmt; +} + /* OpenMP 4.0: # pragma omp declare simd declare-simd-clauses[optseq] new-line */ @@ -31627,6 +32457,33 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok) switch (pragma_tok->pragma_kind) { + case PRAGMA_OACC_CACHE: + stmt = cp_parser_oacc_cache (parser, pragma_tok); + break; + case PRAGMA_OACC_DATA: + stmt = cp_parser_oacc_data (parser, pragma_tok); + break; + case PRAGMA_OACC_ENTER_DATA: + stmt = cp_parser_oacc_enter_exit_data (parser, pragma_tok, true); + break; + case PRAGMA_OACC_EXIT_DATA: + stmt = cp_parser_oacc_enter_exit_data (parser, pragma_tok, false); + break; + case PRAGMA_OACC_KERNELS: + stmt = cp_parser_oacc_kernels (parser, pragma_tok); + break; + case PRAGMA_OACC_LOOP: + stmt = cp_parser_oacc_loop (parser, pragma_tok); + break; + case PRAGMA_OACC_PARALLEL: + stmt = cp_parser_oacc_parallel (parser, pragma_tok); + break; + case PRAGMA_OACC_UPDATE: + stmt = cp_parser_oacc_update (parser, pragma_tok); + break; + case PRAGMA_OACC_WAIT: + stmt = cp_parser_oacc_wait (parser, pragma_tok); + break; case PRAGMA_OMP_ATOMIC: cp_parser_omp_atomic (parser, pragma_tok); return; @@ -32169,6 +33026,15 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context) cp_parser_omp_declare (parser, pragma_tok, context); return false; + case PRAGMA_OACC_CACHE: + case PRAGMA_OACC_DATA: + case PRAGMA_OACC_ENTER_DATA: + case PRAGMA_OACC_EXIT_DATA: + case PRAGMA_OACC_KERNELS: + case PRAGMA_OACC_PARALLEL: + case PRAGMA_OACC_LOOP: + case PRAGMA_OACC_UPDATE: + case PRAGMA_OACC_WAIT: case PRAGMA_OMP_ATOMIC: case PRAGMA_OMP_CRITICAL: case PRAGMA_OMP_DISTRIBUTE: diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 15b8d01..915048d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -66,6 +66,7 @@ along with GCC; see the file COPYING3. If not see #include "omp-low.h" #include "builtins.h" #include "convert.h" +#include "gomp-constants.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or @@ -4670,7 +4671,7 @@ handle_omp_array_sections (tree c) return false; tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); if (!cxx_mark_addressable (t)) return false; OMP_CLAUSE_DECL (c2) = t; @@ -4694,7 +4695,7 @@ handle_omp_array_sections (tree c) { tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (c3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (c3) = ptr; OMP_CLAUSE_DECL (c2) = convert_from_reference (ptr); OMP_CLAUSE_SIZE (c3) = size_zero_node; @@ -5571,6 +5572,44 @@ finish_omp_clauses (tree clauses) } break; + case OMP_CLAUSE_ASYNC: + t = OMP_CLAUSE_ASYNC_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error ("%<async%> expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_ASYNC_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_VECTOR_LENGTH: + t = OMP_CLAUSE_VECTOR_LENGTH_EXPR (c); + t = maybe_convert_cond (t); + if (t == error_mark_node) + remove = true; + else if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_VECTOR_LENGTH_EXPR (c) = t; + break; + + case OMP_CLAUSE_WAIT: + t = OMP_CLAUSE_WAIT_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_WAIT_EXPR (c) = t; + break; + case OMP_CLAUSE_THREAD_LIMIT: t = OMP_CLAUSE_THREAD_LIMIT_EXPR (c); if (t == error_mark_node) @@ -5721,6 +5760,7 @@ finish_omp_clauses (tree clauses) case OMP_CLAUSE_MAP: case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + case OMP_CLAUSE__CACHE_: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST) { @@ -5749,7 +5789,7 @@ finish_omp_clauses (tree clauses) if (processing_template_decl) break; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER) + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER) break; if (DECL_P (t)) error ("%qD is not a variable in %qs clause", t, @@ -5770,7 +5810,7 @@ finish_omp_clauses (tree clauses) && !cxx_mark_addressable (t)) remove = true; else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER) + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER) && !type_dependent_expression_p (t) && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) @@ -6088,6 +6128,60 @@ finish_omp_structured_block (tree block) return do_poplevel (block); } +/* Generate OACC_DATA, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_DATA. */ + +tree +finish_oacc_data (tree clauses, tree block) +{ + tree stmt; + + block = finish_omp_structured_block (block); + + stmt = make_node (OACC_DATA); + TREE_TYPE (stmt) = void_type_node; + OACC_DATA_CLAUSES (stmt) = clauses; + OACC_DATA_BODY (stmt) = block; + + return add_stmt (stmt); +} + +/* Generate OACC_KERNELS, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_KERNELS. */ + +tree +finish_oacc_kernels (tree clauses, tree block) +{ + tree stmt; + + block = finish_omp_structured_block (block); + + stmt = make_node (OACC_KERNELS); + TREE_TYPE (stmt) = void_type_node; + OACC_KERNELS_CLAUSES (stmt) = clauses; + OACC_KERNELS_BODY (stmt) = block; + + return add_stmt (stmt); +} + +/* Generate OACC_PARALLEL, with CLAUSES and BLOCK as its compound + statement. LOC is the location of the OACC_PARALLEL. */ + +tree +finish_oacc_parallel (tree clauses, tree block) +{ + tree stmt; + + block = finish_omp_structured_block (block); + + stmt = make_node (OACC_PARALLEL); + TREE_TYPE (stmt) = void_type_node; + OACC_PARALLEL_CLAUSES (stmt) = clauses; + OACC_PARALLEL_BODY (stmt) = block; + + return add_stmt (stmt); +} + /* Similarly, except force the retention of the BLOCK. */ tree diff --git a/gcc/doc/generic.texi b/gcc/doc/generic.texi index 0e17437..bbafad9 100644 --- a/gcc/doc/generic.texi +++ b/gcc/doc/generic.texi @@ -1819,6 +1819,7 @@ There are also several varieties of complex statements. * Jumps:: * Cleanups:: * OpenMP:: +* OpenACC:: @end menu @node Basic Statements @@ -2093,8 +2094,8 @@ variables. @item OMP_FOR -Represents @code{#pragma omp for [clause1 @dots{} clauseN]}. It -has 5 operands: +Represents @code{#pragma omp for [clause1 @dots{} clauseN]}. It has +six operands: Operand @code{OMP_FOR_BODY} contains the loop body. @@ -2184,10 +2185,9 @@ building code (@code{omp-low.c}). @item OMP_CONTINUE Similarly, this instruction does not represent an OpenMP -directive, it is used by @code{OMP_FOR} and +directive, it is used by @code{OMP_FOR} (and similar codes) as well as @code{OMP_SECTIONS} to mark the place where the code needs to -loop to the next iteration (in the case of @code{OMP_FOR}) or -the next section (in the case of @code{OMP_SECTIONS}). +loop to the next iteration, or the next section, respectively. In some cases, @code{OMP_CONTINUE} is placed right before @code{OMP_RETURN}. But if there are cleanups that need to @@ -2233,6 +2233,67 @@ compilation. @end table +@node OpenACC +@subsection OpenACC +@tindex OACC_CACHE +@tindex OACC_DATA +@tindex OACC_DECLARE +@tindex OACC_ENTER_DATA +@tindex OACC_EXIT_DATA +@tindex OACC_HOST_DATA +@tindex OACC_KERNELS +@tindex OACC_LOOP +@tindex OACC_PARALLEL +@tindex OACC_UPDATE + +All the statements starting with @code{OACC_} represent directives and +clauses used by the OpenACC API @w{@uref{http://www.openacc.org/}}. + +@table @code +@item OACC_CACHE + +Represents @code{#pragma acc cache (var @dots{})}. + +@item OACC_DATA + +Represents @code{#pragma acc data [clause1 @dots{} clauseN]}. + +@item OACC_DECLARE + +Represents @code{#pragma acc declare [clause1 @dots{} clauseN]}. + +@item OACC_ENTER_DATA + +Represents @code{#pragma acc enter data [clause1 @dots{} clauseN]}. + +@item OACC_EXIT_DATA + +Represents @code{#pragma acc exit data [clause1 @dots{} clauseN]}. + +@item OACC_HOST_DATA + +Represents @code{#pragma acc host_data [clause1 @dots{} clauseN]}. + +@item OACC_KERNELS + +Represents @code{#pragma acc kernels [clause1 @dots{} clauseN]}. + +@item OACC_LOOP + +Represents @code{#pragma acc loop [clause1 @dots{} clauseN]}. + +See the description of the @code{OMP_FOR} code. + +@item OACC_PARALLEL + +Represents @code{#pragma acc parallel [clause1 @dots{} clauseN]}. + +@item OACC_UPDATE + +Represents @code{#pragma acc update [clause1 @dots{} clauseN]}. + +@end table + @c --------------------------------------------------------------------- @c Functions @c --------------------------------------------------------------------- diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi index 54daf58..543de90 100644 --- a/gcc/doc/gimple.texi +++ b/gcc/doc/gimple.texi @@ -1828,9 +1828,8 @@ Set @code{NAME} to be the name associated with @code{OMP} critical statement @co tree clauses, tree index, tree initial, tree final, tree incr, @ gimple_seq pre_body, enum tree_code omp_for_cond) Build a @code{GIMPLE_OMP_FOR} statement. @code{BODY} is sequence of statements -inside the for loop. @code{CLAUSES}, are any of the @code{OMP} loop -construct's clauses: private, firstprivate, lastprivate, -reductions, ordered, schedule, and nowait. @code{PRE_BODY} is the +inside the for loop. @code{CLAUSES}, are any of the loop +construct's clauses. @code{PRE_BODY} is the sequence of statements that are loop invariant. @code{INDEX} is the index variable. @code{INITIAL} is the initial value of @code{INDEX}. @code{FINAL} is final value of @code{INDEX}. OMP_FOR_COND is the predicate used to diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 96faf0f..510201a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -168,8 +168,8 @@ in the following sections. @gccoptlist{-ansi -std=@var{standard} -fgnu89-inline @gol -aux-info @var{filename} -fallow-parameterless-variadic-functions @gol -fno-asm -fno-builtin -fno-builtin-@var{function} @gol --fhosted -ffreestanding -fopenmp -fopenmp-simd -fms-extensions @gol --fplan9-extensions -trigraphs -traditional -traditional-cpp @gol +-fhosted -ffreestanding -fopenacc -fopenmp -fopenmp-simd @gol +-fms-extensions -fplan9-extensions -trigraphs -traditional -traditional-cpp @gol -fallow-single-precision -fcond-mismatch -flax-vector-conversions @gol -fsigned-bitfields -fsigned-char @gol -funsigned-bitfields -funsigned-char} @@ -1885,6 +1885,20 @@ This is equivalent to @option{-fno-hosted}. @xref{Standards,,Language Standards Supported by GCC}, for details of freestanding and hosted environments. +@item -fopenacc +@opindex fopenacc +@cindex OpenACC accelerator programming +Enable handling of OpenACC directives @code{#pragma acc} in C/C++ and +@code{!$acc} in Fortran. When @option{-fopenacc} is specified, the +compiler generates accelerated code according to the OpenACC Application +Programming Interface v2.0 @w{@uref{http://www.openacc.org/}}. This option +implies @option{-pthread}, and thus is only supported on targets that +have support for @option{-pthread}. + +Note that this is an experimental feature, incomplete, and subject to +change in future versions of GCC. See +@w{@uref{https://gcc.gnu.org/wiki/OpenACC}} for more information. + @item -fopenmp @opindex fopenmp @cindex OpenMP parallel diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index b8b6a06..738e558 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -1836,6 +1836,9 @@ Target supports Graphite optimizations. @item fixed_point Target supports fixed-point extension to C. +@item fopenacc +Target supports OpenACC via @option{-fopenacc}. + @item fopenmp Target supports OpenMP via @option{-fopenmp}. diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index df4a2f3..d8b72a2 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,199 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + Cesar Philippidis <cesar@codesourcery.com> + James Norris <jnorris@codesourcery.com> + Ilmir Usmanov <i.usmanov@samsung.com> + Tobias Burnus <burnus@net-b.de> + + * lang.opt (fopenacc): New option. + * cpp.c (cpp_define_builtins): Conditionally define _OPENACC. + * dump-parse-tree.c (show_omp_node): Split part of it into... + (show_omp_clauses): ... this new function. + (show_omp_node, show_code_node): Handle EXEC_OACC_PARALLEL_LOOP, + EXEC_OACC_PARALLEL, EXEC_OACC_KERNELS_LOOP, EXEC_OACC_KERNELS, + EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP, + EXEC_OACC_UPDATE, EXEC_OACC_WAIT, EXEC_OACC_CACHE, + EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_DATA. + (show_namespace): Update for OpenACC. + * f95-lang.c (DEF_FUNCTION_TYPE_VAR_2, DEF_FUNCTION_TYPE_VAR_8) + (DEF_FUNCTION_TYPE_VAR_12, DEF_GOACC_BUILTIN) + (DEF_GOACC_BUILTIN_COMPILER): New macros. + * types.def (BT_FN_VOID_INT_INT_VAR) + (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR) + (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR): + New function types. + * gfortran.h (gfc_statement): Add ST_OACC_PARALLEL_LOOP, + ST_OACC_END_PARALLEL_LOOP, ST_OACC_PARALLEL, ST_OACC_END_PARALLEL, + ST_OACC_KERNELS, ST_OACC_END_KERNELS, ST_OACC_DATA, + ST_OACC_END_DATA, ST_OACC_HOST_DATA, ST_OACC_END_HOST_DATA, + ST_OACC_LOOP, ST_OACC_END_LOOP, ST_OACC_DECLARE, ST_OACC_UPDATE, + ST_OACC_WAIT, ST_OACC_CACHE, ST_OACC_KERNELS_LOOP, + ST_OACC_END_KERNELS_LOOP, ST_OACC_ENTER_DATA, ST_OACC_EXIT_DATA, + ST_OACC_ROUTINE. + (struct gfc_expr_list): New data type. + (gfc_get_expr_list): New macro. + (gfc_omp_map_op): Add OMP_MAP_FORCE_ALLOC, OMP_MAP_FORCE_DEALLOC, + OMP_MAP_FORCE_TO, OMP_MAP_FORCE_FROM, OMP_MAP_FORCE_TOFROM, + OMP_MAP_FORCE_PRESENT, OMP_MAP_FORCE_DEVICEPTR. + (OMP_LIST_FIRST, OMP_LIST_DEVICE_RESIDENT, OMP_LIST_USE_DEVICE) + (OMP_LIST_CACHE): New enumerators. + (struct gfc_omp_clauses): Add async_expr, gang_expr, worker_expr, + vector_expr, num_gangs_expr, num_workers_expr, vector_length_expr, + wait_list, tile_list, async, gang, worker, vector, seq, + independent, wait, par_auto, gang_static, and loc members. + (struct gfc_namespace): Add oacc_declare_clauses member. + (gfc_exec_op): Add EXEC_OACC_KERNELS_LOOP, + EXEC_OACC_PARALLEL_LOOP, EXEC_OACC_PARALLEL, EXEC_OACC_KERNELS, + EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP, + EXEC_OACC_UPDATE, EXEC_OACC_WAIT, EXEC_OACC_CACHE, + EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_DATA. + (gfc_free_expr_list, gfc_resolve_oacc_directive) + (gfc_resolve_oacc_declare, gfc_resolve_oacc_parallel_loop_blocks) + (gfc_resolve_oacc_blocks): New prototypes. + * match.c (match_exit_cycle): Handle EXEC_OACC_LOOP and + EXEC_OACC_PARALLEL_LOOP. + * match.h (gfc_match_oacc_cache, gfc_match_oacc_wait) + (gfc_match_oacc_update, gfc_match_oacc_declare) + (gfc_match_oacc_loop, gfc_match_oacc_host_data) + (gfc_match_oacc_data, gfc_match_oacc_kernels) + (gfc_match_oacc_kernels_loop, gfc_match_oacc_parallel) + (gfc_match_oacc_parallel_loop, gfc_match_oacc_enter_data) + (gfc_match_oacc_exit_data, gfc_match_oacc_routine): New + prototypes. + * openmp.c: Include "diagnostic.h" and "gomp-constants.h". + (gfc_free_omp_clauses): Update for members added to struct + gfc_omp_clauses. + (gfc_match_omp_clauses): Change mask paramter to uint64_t. Add + openacc parameter. + (resolve_omp_clauses): Add openacc parameter. Update for OpenACC. + (struct fortran_omp_context): Add is_openmp member. + (gfc_resolve_omp_parallel_blocks): Initialize it. + (gfc_resolve_do_iterator): Update for OpenACC. + (gfc_resolve_omp_directive): Call + resolve_omp_directive_inside_oacc_region. + (OMP_CLAUSE_PRIVATE, OMP_CLAUSE_FIRSTPRIVATE) + (OMP_CLAUSE_LASTPRIVATE, OMP_CLAUSE_COPYPRIVATE) + (OMP_CLAUSE_SHARED, OMP_CLAUSE_COPYIN, OMP_CLAUSE_REDUCTION) + (OMP_CLAUSE_IF, OMP_CLAUSE_NUM_THREADS, OMP_CLAUSE_SCHEDULE) + (OMP_CLAUSE_DEFAULT, OMP_CLAUSE_ORDERED, OMP_CLAUSE_COLLAPSE) + (OMP_CLAUSE_UNTIED, OMP_CLAUSE_FINAL, OMP_CLAUSE_MERGEABLE) + (OMP_CLAUSE_ALIGNED, OMP_CLAUSE_DEPEND, OMP_CLAUSE_INBRANCH) + (OMP_CLAUSE_LINEAR, OMP_CLAUSE_NOTINBRANCH, OMP_CLAUSE_PROC_BIND) + (OMP_CLAUSE_SAFELEN, OMP_CLAUSE_SIMDLEN, OMP_CLAUSE_UNIFORM) + (OMP_CLAUSE_DEVICE, OMP_CLAUSE_MAP, OMP_CLAUSE_TO) + (OMP_CLAUSE_FROM, OMP_CLAUSE_NUM_TEAMS, OMP_CLAUSE_THREAD_LIMIT) + (OMP_CLAUSE_DIST_SCHEDULE): Use uint64_t. + (OMP_CLAUSE_ASYNC, OMP_CLAUSE_NUM_GANGS, OMP_CLAUSE_NUM_WORKERS) + (OMP_CLAUSE_VECTOR_LENGTH, OMP_CLAUSE_COPY, OMP_CLAUSE_COPYOUT) + (OMP_CLAUSE_CREATE, OMP_CLAUSE_PRESENT) + (OMP_CLAUSE_PRESENT_OR_COPY, OMP_CLAUSE_PRESENT_OR_COPYIN) + (OMP_CLAUSE_PRESENT_OR_COPYOUT, OMP_CLAUSE_PRESENT_OR_CREATE) + (OMP_CLAUSE_DEVICEPTR, OMP_CLAUSE_GANG, OMP_CLAUSE_WORKER) + (OMP_CLAUSE_VECTOR, OMP_CLAUSE_SEQ, OMP_CLAUSE_INDEPENDENT) + (OMP_CLAUSE_USE_DEVICE, OMP_CLAUSE_DEVICE_RESIDENT) + (OMP_CLAUSE_HOST_SELF, OMP_CLAUSE_OACC_DEVICE, OMP_CLAUSE_WAIT) + (OMP_CLAUSE_DELETE, OMP_CLAUSE_AUTO, OMP_CLAUSE_TILE): New macros. + (gfc_match_omp_clauses): Handle those. + (OACC_PARALLEL_CLAUSES, OACC_KERNELS_CLAUSES, OACC_DATA_CLAUSES) + (OACC_LOOP_CLAUSES, OACC_PARALLEL_LOOP_CLAUSES) + (OACC_KERNELS_LOOP_CLAUSES, OACC_HOST_DATA_CLAUSES) + (OACC_DECLARE_CLAUSES, OACC_UPDATE_CLAUSES) + (OACC_ENTER_DATA_CLAUSES, OACC_EXIT_DATA_CLAUSES) + (OACC_WAIT_CLAUSES): New macros. + (gfc_free_expr_list, match_oacc_expr_list, match_oacc_clause_gang) + (gfc_match_omp_map_clause, gfc_match_oacc_parallel_loop) + (gfc_match_oacc_parallel, gfc_match_oacc_kernels_loop) + (gfc_match_oacc_kernels, gfc_match_oacc_data) + (gfc_match_oacc_host_data, gfc_match_oacc_loop) + (gfc_match_oacc_declare, gfc_match_oacc_update) + (gfc_match_oacc_enter_data, gfc_match_oacc_exit_data) + (gfc_match_oacc_wait, gfc_match_oacc_cache) + (gfc_match_oacc_routine, oacc_is_loop) + (resolve_oacc_scalar_int_expr, resolve_oacc_positive_int_expr) + (check_symbol_not_pointer, check_array_not_assumed) + (resolve_oacc_data_clauses, resolve_oacc_deviceptr_clause) + (oacc_compatible_clauses, oacc_is_parallel, oacc_is_kernels) + (omp_code_to_statement, oacc_code_to_statement) + (resolve_oacc_directive_inside_omp_region) + (resolve_omp_directive_inside_oacc_region) + (resolve_oacc_nested_loops, resolve_oacc_params_in_parallel) + (resolve_oacc_loop_blocks, gfc_resolve_oacc_blocks) + (resolve_oacc_loop, resolve_oacc_cache, gfc_resolve_oacc_declare) + (gfc_resolve_oacc_directive): New functions. + * parse.c (next_free): Update for OpenACC. Move some code into... + (verify_token_free): ... this new function. + (next_fixed): Update for OpenACC. Move some code into... + (verify_token_fixed): ... this new function. + (case_executable): Add ST_OACC_UPDATE, ST_OACC_WAIT, + ST_OACC_CACHE, ST_OACC_ENTER_DATA, and ST_OACC_EXIT_DATA. + (case_exec_markers): Add ST_OACC_PARALLEL_LOOP, ST_OACC_PARALLEL, + ST_OACC_KERNELS, ST_OACC_DATA, ST_OACC_HOST_DATA, ST_OACC_LOOP, + ST_OACC_KERNELS_LOOP. + (case_decl): Add ST_OACC_ROUTINE. + (push_state, parse_critical_block, parse_progunit): Update for + OpenACC. + (gfc_ascii_statement): Handle ST_OACC_PARALLEL_LOOP, + ST_OACC_END_PARALLEL_LOOP, ST_OACC_PARALLEL, ST_OACC_END_PARALLEL, + ST_OACC_KERNELS, ST_OACC_END_KERNELS, ST_OACC_KERNELS_LOOP, + ST_OACC_END_KERNELS_LOOP, ST_OACC_DATA, ST_OACC_END_DATA, + ST_OACC_HOST_DATA, ST_OACC_END_HOST_DATA, ST_OACC_LOOP, + ST_OACC_END_LOOP, ST_OACC_DECLARE, ST_OACC_UPDATE, ST_OACC_WAIT, + ST_OACC_CACHE, ST_OACC_ENTER_DATA, ST_OACC_EXIT_DATA, + ST_OACC_ROUTINE. + (verify_st_order, parse_spec): Handle ST_OACC_DECLARE. + (parse_executable): Handle ST_OACC_PARALLEL_LOOP, + ST_OACC_KERNELS_LOOP, ST_OACC_LOOP, ST_OACC_PARALLEL, + ST_OACC_KERNELS, ST_OACC_DATA, ST_OACC_HOST_DATA. + (decode_oacc_directive, parse_oacc_structured_block) + (parse_oacc_loop, is_oacc): New functions. + * parse.h (struct gfc_state_data): Add oacc_declare_clauses + member. + (is_oacc): New prototype. + * resolve.c (gfc_resolve_blocks, gfc_resolve_code): Handle + EXEC_OACC_PARALLEL_LOOP, EXEC_OACC_PARALLEL, + EXEC_OACC_KERNELS_LOOP, EXEC_OACC_KERNELS, EXEC_OACC_DATA, + EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP, EXEC_OACC_UPDATE, + EXEC_OACC_WAIT, EXEC_OACC_CACHE, EXEC_OACC_ENTER_DATA, + EXEC_OACC_EXIT_DATA. + (resolve_codes): Call gfc_resolve_oacc_declare. + * scanner.c (openacc_flag, openacc_locus): New variables. + (skip_free_comments): Update for OpenACC. Move some code into... + (skip_omp_attribute): ... this new function. + (skip_oacc_attribute): New function. + (skip_fixed_comments, gfc_next_char_literal): Update for OpenACC. + * st.c (gfc_free_statement): Handle EXEC_OACC_PARALLEL_LOOP, + EXEC_OACC_PARALLEL, EXEC_OACC_KERNELS_LOOP, EXEC_OACC_KERNELS, + EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, EXEC_OACC_LOOP, + EXEC_OACC_UPDATE, EXEC_OACC_WAIT, EXEC_OACC_CACHE, + EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_DATA. + * trans-decl.c (gfc_generate_function_code): Update for OpenACC. + * trans-openmp.c: Include "gomp-constants.h". + (gfc_omp_finish_clause, gfc_trans_omp_clauses): Use GOMP_MAP_* + instead of OMP_CLAUSE_MAP_*. Use OMP_CLAUSE_SET_MAP_KIND. + (gfc_trans_omp_clauses): Handle OMP_LIST_USE_DEVICE, + OMP_LIST_DEVICE_RESIDENT, OMP_LIST_CACHE, and OMP_MAP_FORCE_ALLOC, + OMP_MAP_FORCE_DEALLOC, OMP_MAP_FORCE_TO, OMP_MAP_FORCE_FROM, + OMP_MAP_FORCE_TOFROM, OMP_MAP_FORCE_PRESENT, + OMP_MAP_FORCE_DEVICEPTR, and gfc_omp_clauses' async, seq, + independent, wait_list, num_gangs_expr, num_workers_expr, + vector_length_expr, vector, vector_expr, worker, worker_expr, + gang, gang_expr members. + (gfc_trans_omp_do): Handle EXEC_OACC_LOOP. + (gfc_convert_expr_to_tree, gfc_trans_oacc_construct) + (gfc_trans_oacc_executable_directive) + (gfc_trans_oacc_wait_directive, gfc_trans_oacc_combined_directive) + (gfc_trans_oacc_declare, gfc_trans_oacc_directive): New functions. + * trans-stmt.c (gfc_trans_block_construct): Update for OpenACC. + * trans-stmt.h (gfc_trans_oacc_directive, gfc_trans_oacc_declare): + New prototypes. + * trans.c (tranc_code): Handle EXEC_OACC_CACHE, EXEC_OACC_WAIT, + EXEC_OACC_UPDATE, EXEC_OACC_LOOP, EXEC_OACC_HOST_DATA, + EXEC_OACC_DATA, EXEC_OACC_KERNELS, EXEC_OACC_KERNELS_LOOP, + EXEC_OACC_PARALLEL, EXEC_OACC_PARALLEL_LOOP, EXEC_OACC_ENTER_DATA, + EXEC_OACC_EXIT_DATA. + * gfortran.texi: Update for OpenACC. + * intrinsic.texi: Likewise. + * invoke.texi: Likewise. + 2015-01-15 Janus Weil <janus@gcc.gnu.org> PR fortran/58023 diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c index b30f90e..e239f21 100644 --- a/gcc/fortran/cpp.c +++ b/gcc/fortran/cpp.c @@ -179,6 +179,9 @@ cpp_define_builtins (cpp_reader *pfile) cpp_define (pfile, "__GFORTRAN__=1"); cpp_define (pfile, "_LANGUAGE_FORTRAN=1"); + if (flag_openacc) + cpp_define (pfile, "_OPENACC=201306"); + if (flag_openmp) cpp_define (pfile, "_OPENMP=201307"); diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 6d587c2..83ecbaa 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1072,7 +1072,265 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n) } } -/* Show a single OpenMP directive node and everything underneath it + +/* Show OpenMP or OpenACC clauses. */ + +static void +show_omp_clauses (gfc_omp_clauses *omp_clauses) +{ + int list_type; + + switch (omp_clauses->cancel) + { + case OMP_CANCEL_UNKNOWN: + break; + case OMP_CANCEL_PARALLEL: + fputs (" PARALLEL", dumpfile); + break; + case OMP_CANCEL_SECTIONS: + fputs (" SECTIONS", dumpfile); + break; + case OMP_CANCEL_DO: + fputs (" DO", dumpfile); + break; + case OMP_CANCEL_TASKGROUP: + fputs (" TASKGROUP", dumpfile); + break; + } + if (omp_clauses->if_expr) + { + fputs (" IF(", dumpfile); + show_expr (omp_clauses->if_expr); + fputc (')', dumpfile); + } + if (omp_clauses->final_expr) + { + fputs (" FINAL(", dumpfile); + show_expr (omp_clauses->final_expr); + fputc (')', dumpfile); + } + if (omp_clauses->num_threads) + { + fputs (" NUM_THREADS(", dumpfile); + show_expr (omp_clauses->num_threads); + fputc (')', dumpfile); + } + if (omp_clauses->async) + { + fputs (" ASYNC", dumpfile); + if (omp_clauses->async_expr) + { + fputc ('(', dumpfile); + show_expr (omp_clauses->async_expr); + fputc (')', dumpfile); + } + } + if (omp_clauses->num_gangs_expr) + { + fputs (" NUM_GANGS(", dumpfile); + show_expr (omp_clauses->num_gangs_expr); + fputc (')', dumpfile); + } + if (omp_clauses->num_workers_expr) + { + fputs (" NUM_WORKERS(", dumpfile); + show_expr (omp_clauses->num_workers_expr); + fputc (')', dumpfile); + } + if (omp_clauses->vector_length_expr) + { + fputs (" VECTOR_LENGTH(", dumpfile); + show_expr (omp_clauses->vector_length_expr); + fputc (')', dumpfile); + } + if (omp_clauses->gang) + { + fputs (" GANG", dumpfile); + if (omp_clauses->gang_expr) + { + fputc ('(', dumpfile); + show_expr (omp_clauses->gang_expr); + fputc (')', dumpfile); + } + } + if (omp_clauses->worker) + { + fputs (" WORKER", dumpfile); + if (omp_clauses->worker_expr) + { + fputc ('(', dumpfile); + show_expr (omp_clauses->worker_expr); + fputc (')', dumpfile); + } + } + if (omp_clauses->vector) + { + fputs (" VECTOR", dumpfile); + if (omp_clauses->vector_expr) + { + fputc ('(', dumpfile); + show_expr (omp_clauses->vector_expr); + fputc (')', dumpfile); + } + } + if (omp_clauses->sched_kind != OMP_SCHED_NONE) + { + const char *type; + switch (omp_clauses->sched_kind) + { + case OMP_SCHED_STATIC: type = "STATIC"; break; + case OMP_SCHED_DYNAMIC: type = "DYNAMIC"; break; + case OMP_SCHED_GUIDED: type = "GUIDED"; break; + case OMP_SCHED_RUNTIME: type = "RUNTIME"; break; + case OMP_SCHED_AUTO: type = "AUTO"; break; + default: + gcc_unreachable (); + } + fprintf (dumpfile, " SCHEDULE (%s", type); + if (omp_clauses->chunk_size) + { + fputc (',', dumpfile); + show_expr (omp_clauses->chunk_size); + } + fputc (')', dumpfile); + } + if (omp_clauses->default_sharing != OMP_DEFAULT_UNKNOWN) + { + const char *type; + switch (omp_clauses->default_sharing) + { + case OMP_DEFAULT_NONE: type = "NONE"; break; + case OMP_DEFAULT_PRIVATE: type = "PRIVATE"; break; + case OMP_DEFAULT_SHARED: type = "SHARED"; break; + case OMP_DEFAULT_FIRSTPRIVATE: type = "FIRSTPRIVATE"; break; + default: + gcc_unreachable (); + } + fprintf (dumpfile, " DEFAULT(%s)", type); + } + if (omp_clauses->tile_list) + { + gfc_expr_list *list; + fputs (" TILE(", dumpfile); + for (list = omp_clauses->tile_list; list; list = list->next) + { + show_expr (list->expr); + if (list->next) + fputs (", ", dumpfile); + } + fputc (')', dumpfile); + } + if (omp_clauses->wait_list) + { + gfc_expr_list *list; + fputs (" WAIT(", dumpfile); + for (list = omp_clauses->wait_list; list; list = list->next) + { + show_expr (list->expr); + if (list->next) + fputs (", ", dumpfile); + } + fputc (')', dumpfile); + } + if (omp_clauses->seq) + fputs (" SEQ", dumpfile); + if (omp_clauses->independent) + fputs (" INDEPENDENT", dumpfile); + if (omp_clauses->ordered) + fputs (" ORDERED", dumpfile); + if (omp_clauses->untied) + fputs (" UNTIED", dumpfile); + if (omp_clauses->mergeable) + fputs (" MERGEABLE", dumpfile); + if (omp_clauses->collapse) + fprintf (dumpfile, " COLLAPSE(%d)", omp_clauses->collapse); + for (list_type = 0; list_type < OMP_LIST_NUM; list_type++) + if (omp_clauses->lists[list_type] != NULL + && list_type != OMP_LIST_COPYPRIVATE) + { + const char *type = NULL; + switch (list_type) + { + case OMP_LIST_USE_DEVICE: type = "USE_DEVICE"; break; + case OMP_LIST_DEVICE_RESIDENT: type = "USE_DEVICE"; break; + case OMP_LIST_CACHE: type = ""; break; + case OMP_LIST_PRIVATE: type = "PRIVATE"; break; + case OMP_LIST_FIRSTPRIVATE: type = "FIRSTPRIVATE"; break; + case OMP_LIST_LASTPRIVATE: type = "LASTPRIVATE"; break; + case OMP_LIST_SHARED: type = "SHARED"; break; + case OMP_LIST_COPYIN: type = "COPYIN"; break; + case OMP_LIST_UNIFORM: type = "UNIFORM"; break; + case OMP_LIST_ALIGNED: type = "ALIGNED"; break; + case OMP_LIST_LINEAR: type = "LINEAR"; break; + case OMP_LIST_REDUCTION: type = "REDUCTION"; break; + case OMP_LIST_DEPEND: type = "DEPEND"; break; + default: + gcc_unreachable (); + } + fprintf (dumpfile, " %s(", type); + show_omp_namelist (list_type, omp_clauses->lists[list_type]); + fputc (')', dumpfile); + } + if (omp_clauses->safelen_expr) + { + fputs (" SAFELEN(", dumpfile); + show_expr (omp_clauses->safelen_expr); + fputc (')', dumpfile); + } + if (omp_clauses->simdlen_expr) + { + fputs (" SIMDLEN(", dumpfile); + show_expr (omp_clauses->simdlen_expr); + fputc (')', dumpfile); + } + if (omp_clauses->inbranch) + fputs (" INBRANCH", dumpfile); + if (omp_clauses->notinbranch) + fputs (" NOTINBRANCH", dumpfile); + if (omp_clauses->proc_bind != OMP_PROC_BIND_UNKNOWN) + { + const char *type; + switch (omp_clauses->proc_bind) + { + case OMP_PROC_BIND_MASTER: type = "MASTER"; break; + case OMP_PROC_BIND_SPREAD: type = "SPREAD"; break; + case OMP_PROC_BIND_CLOSE: type = "CLOSE"; break; + default: + gcc_unreachable (); + } + fprintf (dumpfile, " PROC_BIND(%s)", type); + } + if (omp_clauses->num_teams) + { + fputs (" NUM_TEAMS(", dumpfile); + show_expr (omp_clauses->num_teams); + fputc (')', dumpfile); + } + if (omp_clauses->device) + { + fputs (" DEVICE(", dumpfile); + show_expr (omp_clauses->device); + fputc (')', dumpfile); + } + if (omp_clauses->thread_limit) + { + fputs (" THREAD_LIMIT(", dumpfile); + show_expr (omp_clauses->thread_limit); + fputc (')', dumpfile); + } + if (omp_clauses->dist_sched_kind != OMP_SCHED_NONE) + { + fprintf (dumpfile, " DIST_SCHEDULE (static"); + if (omp_clauses->dist_chunk_size) + { + fputc (',', dumpfile); + show_expr (omp_clauses->dist_chunk_size); + } + fputc (')', dumpfile); + } +} + +/* Show a single OpenMP or OpenACC directive node and everything underneath it if necessary. */ static void @@ -1080,9 +1338,22 @@ show_omp_node (int level, gfc_code *c) { gfc_omp_clauses *omp_clauses = NULL; const char *name = NULL; + bool is_oacc = false; switch (c->op) { + case EXEC_OACC_PARALLEL_LOOP: name = "PARALLEL LOOP"; is_oacc = true; break; + case EXEC_OACC_PARALLEL: name = "PARALLEL"; is_oacc = true; break; + case EXEC_OACC_KERNELS_LOOP: name = "KERNELS LOOP"; is_oacc = true; break; + case EXEC_OACC_KERNELS: name = "KERNELS"; is_oacc = true; break; + case EXEC_OACC_DATA: name = "DATA"; is_oacc = true; break; + case EXEC_OACC_HOST_DATA: name = "HOST_DATA"; is_oacc = true; break; + case EXEC_OACC_LOOP: name = "LOOP"; is_oacc = true; break; + case EXEC_OACC_UPDATE: name = "UPDATE"; is_oacc = true; break; + case EXEC_OACC_WAIT: name = "WAIT"; is_oacc = true; break; + case EXEC_OACC_CACHE: name = "CACHE"; is_oacc = true; break; + case EXEC_OACC_ENTER_DATA: name = "ENTER DATA"; is_oacc = true; break; + case EXEC_OACC_EXIT_DATA: name = "EXIT DATA"; is_oacc = true; break; case EXEC_OMP_ATOMIC: name = "ATOMIC"; break; case EXEC_OMP_BARRIER: name = "BARRIER"; break; case EXEC_OMP_CANCEL: name = "CANCEL"; break; @@ -1109,9 +1380,21 @@ show_omp_node (int level, gfc_code *c) default: gcc_unreachable (); } - fprintf (dumpfile, "!$OMP %s", name); + fprintf (dumpfile, "!$%s %s", is_oacc ? "ACC" : "OMP", name); switch (c->op) { + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: case EXEC_OMP_CANCEL: case EXEC_OMP_CANCELLATION_POINT: case EXEC_OMP_DO: @@ -1148,170 +1431,13 @@ show_omp_node (int level, gfc_code *c) break; } if (omp_clauses) - { - int list_type; - - switch (omp_clauses->cancel) - { - case OMP_CANCEL_UNKNOWN: - break; - case OMP_CANCEL_PARALLEL: - fputs (" PARALLEL", dumpfile); - break; - case OMP_CANCEL_SECTIONS: - fputs (" SECTIONS", dumpfile); - break; - case OMP_CANCEL_DO: - fputs (" DO", dumpfile); - break; - case OMP_CANCEL_TASKGROUP: - fputs (" TASKGROUP", dumpfile); - break; - } - if (omp_clauses->if_expr) - { - fputs (" IF(", dumpfile); - show_expr (omp_clauses->if_expr); - fputc (')', dumpfile); - } - if (omp_clauses->final_expr) - { - fputs (" FINAL(", dumpfile); - show_expr (omp_clauses->final_expr); - fputc (')', dumpfile); - } - if (omp_clauses->num_threads) - { - fputs (" NUM_THREADS(", dumpfile); - show_expr (omp_clauses->num_threads); - fputc (')', dumpfile); - } - if (omp_clauses->sched_kind != OMP_SCHED_NONE) - { - const char *type; - switch (omp_clauses->sched_kind) - { - case OMP_SCHED_STATIC: type = "STATIC"; break; - case OMP_SCHED_DYNAMIC: type = "DYNAMIC"; break; - case OMP_SCHED_GUIDED: type = "GUIDED"; break; - case OMP_SCHED_RUNTIME: type = "RUNTIME"; break; - case OMP_SCHED_AUTO: type = "AUTO"; break; - default: - gcc_unreachable (); - } - fprintf (dumpfile, " SCHEDULE (%s", type); - if (omp_clauses->chunk_size) - { - fputc (',', dumpfile); - show_expr (omp_clauses->chunk_size); - } - fputc (')', dumpfile); - } - if (omp_clauses->default_sharing != OMP_DEFAULT_UNKNOWN) - { - const char *type; - switch (omp_clauses->default_sharing) - { - case OMP_DEFAULT_NONE: type = "NONE"; break; - case OMP_DEFAULT_PRIVATE: type = "PRIVATE"; break; - case OMP_DEFAULT_SHARED: type = "SHARED"; break; - case OMP_DEFAULT_FIRSTPRIVATE: type = "FIRSTPRIVATE"; break; - default: - gcc_unreachable (); - } - fprintf (dumpfile, " DEFAULT(%s)", type); - } - if (omp_clauses->ordered) - fputs (" ORDERED", dumpfile); - if (omp_clauses->untied) - fputs (" UNTIED", dumpfile); - if (omp_clauses->mergeable) - fputs (" MERGEABLE", dumpfile); - if (omp_clauses->collapse) - fprintf (dumpfile, " COLLAPSE(%d)", omp_clauses->collapse); - for (list_type = 0; list_type < OMP_LIST_NUM; list_type++) - if (omp_clauses->lists[list_type] != NULL - && list_type != OMP_LIST_COPYPRIVATE) - { - const char *type = NULL; - switch (list_type) - { - case OMP_LIST_PRIVATE: type = "PRIVATE"; break; - case OMP_LIST_FIRSTPRIVATE: type = "FIRSTPRIVATE"; break; - case OMP_LIST_LASTPRIVATE: type = "LASTPRIVATE"; break; - case OMP_LIST_SHARED: type = "SHARED"; break; - case OMP_LIST_COPYIN: type = "COPYIN"; break; - case OMP_LIST_UNIFORM: type = "UNIFORM"; break; - case OMP_LIST_ALIGNED: type = "ALIGNED"; break; - case OMP_LIST_LINEAR: type = "LINEAR"; break; - case OMP_LIST_REDUCTION: type = "REDUCTION"; break; - case OMP_LIST_DEPEND: type = "DEPEND"; break; - default: - gcc_unreachable (); - } - fprintf (dumpfile, " %s(", type); - show_omp_namelist (list_type, omp_clauses->lists[list_type]); - fputc (')', dumpfile); - } - if (omp_clauses->safelen_expr) - { - fputs (" SAFELEN(", dumpfile); - show_expr (omp_clauses->safelen_expr); - fputc (')', dumpfile); - } - if (omp_clauses->simdlen_expr) - { - fputs (" SIMDLEN(", dumpfile); - show_expr (omp_clauses->simdlen_expr); - fputc (')', dumpfile); - } - if (omp_clauses->inbranch) - fputs (" INBRANCH", dumpfile); - if (omp_clauses->notinbranch) - fputs (" NOTINBRANCH", dumpfile); - if (omp_clauses->proc_bind != OMP_PROC_BIND_UNKNOWN) - { - const char *type; - switch (omp_clauses->proc_bind) - { - case OMP_PROC_BIND_MASTER: type = "MASTER"; break; - case OMP_PROC_BIND_SPREAD: type = "SPREAD"; break; - case OMP_PROC_BIND_CLOSE: type = "CLOSE"; break; - default: - gcc_unreachable (); - } - fprintf (dumpfile, " PROC_BIND(%s)", type); - } - if (omp_clauses->num_teams) - { - fputs (" NUM_TEAMS(", dumpfile); - show_expr (omp_clauses->num_teams); - fputc (')', dumpfile); - } - if (omp_clauses->device) - { - fputs (" DEVICE(", dumpfile); - show_expr (omp_clauses->device); - fputc (')', dumpfile); - } - if (omp_clauses->thread_limit) - { - fputs (" THREAD_LIMIT(", dumpfile); - show_expr (omp_clauses->thread_limit); - fputc (')', dumpfile); - } - if (omp_clauses->dist_sched_kind != OMP_SCHED_NONE) - { - fprintf (dumpfile, " DIST_SCHEDULE (static"); - if (omp_clauses->dist_chunk_size) - { - fputc (',', dumpfile); - show_expr (omp_clauses->dist_chunk_size); - } - fputc (')', dumpfile); - } - } + show_omp_clauses (omp_clauses); fputc ('\n', dumpfile); + + /* OpenACC executable directives don't have associated blocks. */ + if (c->op == EXEC_OACC_CACHE || c->op == EXEC_OACC_UPDATE + || c->op == EXEC_OACC_ENTER_DATA || c->op == EXEC_OACC_EXIT_DATA) + return; if (c->op == EXEC_OMP_SECTIONS || c->op == EXEC_OMP_PARALLEL_SECTIONS) { gfc_code *d = c->block; @@ -1331,7 +1457,7 @@ show_omp_node (int level, gfc_code *c) return; fputc ('\n', dumpfile); code_indent (level, 0); - fprintf (dumpfile, "!$OMP END %s", name); + fprintf (dumpfile, "!$%s END %s", is_oacc ? "ACC" : "OMP", name); if (omp_clauses != NULL) { if (omp_clauses->lists[OMP_LIST_COPYPRIVATE]) @@ -2311,6 +2437,18 @@ show_code_node (int level, gfc_code *c) fprintf (dumpfile, " EOR=%d", dt->eor->value); break; + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: case EXEC_OMP_ATOMIC: case EXEC_OMP_CANCEL: case EXEC_OMP_CANCELLATION_POINT: @@ -2432,6 +2570,14 @@ show_namespace (gfc_namespace *ns) for (eq = ns->equiv; eq; eq = eq->next) show_equiv (eq); + if (ns->oacc_declare_clauses) + { + /* Dump !$ACC DECLARE clauses. */ + show_indent (); + fprintf (dumpfile, "!$ACC DECLARE"); + show_omp_clauses (ns->oacc_declare_clauses); + } + fputc ('\n', dumpfile); show_indent (); fputs ("code:", dumpfile); diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index ff57de0..449f01a 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -672,6 +672,11 @@ gfc_init_builtin_functions (void) #define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ ARG6, ARG7, ARG8) NAME, #define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "types.def" #undef DEF_PRIMITIVE_TYPE @@ -685,6 +690,9 @@ gfc_init_builtin_functions (void) #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE BT_LAST }; @@ -1119,6 +1127,42 @@ gfc_init_builtin_functions (void) builtin_types[(int) ENUM] \ = build_varargs_function_type_list (builtin_types[(int) RETURN], \ NULL_TREE); +#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ + builtin_types[(int) ENUM] \ + = build_varargs_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + builtin_types[(int) ARG2], \ + NULL_TREE); +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + builtin_types[(int) ENUM] \ + = build_varargs_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + builtin_types[(int) ARG2], \ + builtin_types[(int) ARG3], \ + builtin_types[(int) ARG4], \ + builtin_types[(int) ARG5], \ + builtin_types[(int) ARG6], \ + builtin_types[(int) ARG7], \ + builtin_types[(int) ARG8], \ + NULL_TREE); +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \ + builtin_types[(int) ENUM] \ + = build_varargs_function_type_list (builtin_types[(int) RETURN], \ + builtin_types[(int) ARG1], \ + builtin_types[(int) ARG2], \ + builtin_types[(int) ARG3], \ + builtin_types[(int) ARG4], \ + builtin_types[(int) ARG5], \ + builtin_types[(int) ARG6], \ + builtin_types[(int) ARG7], \ + builtin_types[(int) ARG8], \ + builtin_types[(int) ARG9], \ + builtin_types[(int) ARG10], \ + builtin_types[(int) ARG11], \ + builtin_types[(int) ARG12], \ + NULL_TREE); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[(int) ENUM] \ = build_pointer_type (builtin_types[(int) TYPE]); @@ -1134,6 +1178,9 @@ gfc_init_builtin_functions (void) #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE builtin_types[(int) BT_LAST] = NULL_TREE; @@ -1145,13 +1192,36 @@ gfc_init_builtin_functions (void) #include "../sync-builtins.def" #undef DEF_SYNC_BUILTIN + if (flag_openacc) + { +#undef DEF_GOACC_BUILTIN +#define DEF_GOACC_BUILTIN(code, name, type, attr) \ + gfc_define_builtin ("__builtin_" name, builtin_types[type], \ + code, name, attr); +#undef DEF_GOACC_BUILTIN_COMPILER +#define DEF_GOACC_BUILTIN_COMPILER(code, name, type, attr) \ + gfc_define_builtin (name, builtin_types[type], code, name, attr); +#undef DEF_GOMP_BUILTIN +#define DEF_GOMP_BUILTIN(code, name, type, attr) /* ignore */ +#include "../omp-builtins.def" +#undef DEF_GOACC_BUILTIN +#undef DEF_GOACC_BUILTIN_COMPILER +#undef DEF_GOMP_BUILTIN + } + if (flag_openmp || flag_openmp_simd || flag_tree_parallelize_loops) { +#undef DEF_GOACC_BUILTIN +#define DEF_GOACC_BUILTIN(code, name, type, attr) /* ignore */ +#undef DEF_GOACC_BUILTIN_COMPILER +#define DEF_GOACC_BUILTIN_COMPILER(code, name, type, attr) /* ignore */ #undef DEF_GOMP_BUILTIN #define DEF_GOMP_BUILTIN(code, name, type, attr) \ gfc_define_builtin ("__builtin_" name, builtin_types[type], \ code, name, attr); #include "../omp-builtins.def" +#undef DEF_GOACC_BUILTIN +#undef DEF_GOACC_BUILTIN_COMPILER #undef DEF_GOMP_BUILTIN } diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 435fd63..4e20895 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -216,6 +216,12 @@ typedef enum ST_WRITE, ST_ASSIGNMENT, ST_POINTER_ASSIGNMENT, ST_SELECT_CASE, ST_SEQUENCE, ST_SIMPLE_IF, ST_STATEMENT_FUNCTION, ST_DERIVED_DECL, ST_LABEL_ASSIGNMENT, ST_ENUM, ST_ENUMERATOR, ST_END_ENUM, ST_SELECT_TYPE, ST_TYPE_IS, ST_CLASS_IS, + ST_OACC_PARALLEL_LOOP, ST_OACC_END_PARALLEL_LOOP, ST_OACC_PARALLEL, + ST_OACC_END_PARALLEL, ST_OACC_KERNELS, ST_OACC_END_KERNELS, ST_OACC_DATA, + ST_OACC_END_DATA, ST_OACC_HOST_DATA, ST_OACC_END_HOST_DATA, ST_OACC_LOOP, + ST_OACC_END_LOOP, ST_OACC_DECLARE, ST_OACC_UPDATE, ST_OACC_WAIT, + ST_OACC_CACHE, ST_OACC_KERNELS_LOOP, ST_OACC_END_KERNELS_LOOP, + ST_OACC_ENTER_DATA, ST_OACC_EXIT_DATA, ST_OACC_ROUTINE, ST_OMP_ATOMIC, ST_OMP_BARRIER, ST_OMP_CRITICAL, ST_OMP_END_ATOMIC, ST_OMP_END_CRITICAL, ST_OMP_END_DO, ST_OMP_END_MASTER, ST_OMP_END_ORDERED, ST_OMP_END_PARALLEL, ST_OMP_END_PARALLEL_DO, ST_OMP_END_PARALLEL_SECTIONS, @@ -1067,6 +1073,16 @@ gfc_namelist; #define gfc_get_namelist() XCNEW (gfc_namelist) +/* Likewise to gfc_namelist, but contains expressions. */ +typedef struct gfc_expr_list +{ + struct gfc_expr *expr; + struct gfc_expr_list *next; +} +gfc_expr_list; + +#define gfc_get_expr_list() XCNEW (gfc_expr_list) + typedef enum { OMP_REDUCTION_NONE = -1, @@ -1099,7 +1115,14 @@ typedef enum OMP_MAP_ALLOC, OMP_MAP_TO, OMP_MAP_FROM, - OMP_MAP_TOFROM + OMP_MAP_TOFROM, + OMP_MAP_FORCE_ALLOC, + OMP_MAP_FORCE_DEALLOC, + OMP_MAP_FORCE_TO, + OMP_MAP_FORCE_FROM, + OMP_MAP_FORCE_TOFROM, + OMP_MAP_FORCE_PRESENT, + OMP_MAP_FORCE_DEVICEPTR } gfc_omp_map_op; @@ -1125,7 +1148,8 @@ gfc_omp_namelist; enum { - OMP_LIST_PRIVATE, + OMP_LIST_FIRST, + OMP_LIST_PRIVATE = OMP_LIST_FIRST, OMP_LIST_FIRSTPRIVATE, OMP_LIST_LASTPRIVATE, OMP_LIST_COPYPRIVATE, @@ -1139,6 +1163,9 @@ enum OMP_LIST_TO, OMP_LIST_FROM, OMP_LIST_REDUCTION, + OMP_LIST_DEVICE_RESIDENT, + OMP_LIST_USE_DEVICE, + OMP_LIST_CACHE, OMP_LIST_NUM }; @@ -1202,6 +1229,21 @@ typedef struct gfc_omp_clauses struct gfc_expr *thread_limit; enum gfc_omp_sched_kind dist_sched_kind; struct gfc_expr *dist_chunk_size; + + /* OpenACC. */ + struct gfc_expr *async_expr; + struct gfc_expr *gang_expr; + struct gfc_expr *worker_expr; + struct gfc_expr *vector_expr; + struct gfc_expr *num_gangs_expr; + struct gfc_expr *num_workers_expr; + struct gfc_expr *vector_length_expr; + gfc_expr_list *wait_list; + gfc_expr_list *tile_list; + unsigned async:1, gang:1, worker:1, vector:1, seq:1, independent:1; + unsigned wait:1, par_auto:1, gang_static:1; + locus loc; + } gfc_omp_clauses; @@ -1609,6 +1651,9 @@ typedef struct gfc_namespace this namespace. */ struct gfc_data *data, *old_data; + /* !$ACC DECLARE clauses. */ + gfc_omp_clauses *oacc_declare_clauses; + gfc_charlen *cl_list, *old_cl_list; gfc_dt_list *derived_types; @@ -2276,6 +2321,10 @@ typedef enum EXEC_READ, EXEC_WRITE, EXEC_IOLENGTH, EXEC_TRANSFER, EXEC_DT_END, EXEC_BACKSPACE, EXEC_ENDFILE, EXEC_INQUIRE, EXEC_REWIND, EXEC_FLUSH, EXEC_LOCK, EXEC_UNLOCK, + EXEC_OACC_KERNELS_LOOP, EXEC_OACC_PARALLEL_LOOP, + EXEC_OACC_PARALLEL, EXEC_OACC_KERNELS, EXEC_OACC_DATA, EXEC_OACC_HOST_DATA, + EXEC_OACC_LOOP, EXEC_OACC_UPDATE, EXEC_OACC_WAIT, EXEC_OACC_CACHE, + EXEC_OACC_ENTER_DATA, EXEC_OACC_EXIT_DATA, EXEC_OMP_CRITICAL, EXEC_OMP_DO, EXEC_OMP_FLUSH, EXEC_OMP_MASTER, EXEC_OMP_ORDERED, EXEC_OMP_PARALLEL, EXEC_OMP_PARALLEL_DO, EXEC_OMP_PARALLEL_SECTIONS, EXEC_OMP_PARALLEL_WORKSHARE, @@ -2877,6 +2926,11 @@ void gfc_resolve_omp_declare_simd (gfc_namespace *); void gfc_resolve_omp_udrs (gfc_symtree *); void gfc_omp_save_and_clear_state (struct gfc_omp_saved_state *); void gfc_omp_restore_state (struct gfc_omp_saved_state *); +void gfc_free_expr_list (gfc_expr_list *); +void gfc_resolve_oacc_directive (gfc_code *, gfc_namespace *); +void gfc_resolve_oacc_declare (gfc_namespace *); +void gfc_resolve_oacc_parallel_loop_blocks (gfc_code *, gfc_namespace *); +void gfc_resolve_oacc_blocks (gfc_code *, gfc_namespace *); /* expr.c */ void gfc_free_actual_arglist (gfc_actual_arglist *); diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi index 5cc624a..300b8b8 100644 --- a/gcc/fortran/gfortran.texi +++ b/gcc/fortran/gfortran.texi @@ -477,6 +477,10 @@ used on real-world programs. In particular, the supported extensions include OpenMP, Cray-style pointers, and several Fortran 2003 and Fortran 2008 features, including TR 15581. However, it is still under development and has a few remaining rough edges. +There also is initial support for OpenACC. +Note that this is an experimental feature, incomplete, and subject to +change in future versions of GCC. See +@uref{https://gcc.gnu.org/wiki/OpenACC} for more information. At present, the GNU Fortran compiler passes the @uref{http://www.fortran-2000.com/ArnaudRecipes/fcvs21_f95.html, @@ -533,6 +537,11 @@ The current status of the support is can be found in the Additionally, the GNU Fortran compilers supports the OpenMP specification (version 4.0, @url{http://openmp.org/@/wp/@/openmp-specifications/}). +There also is initial support for the OpenACC specification (targeting +version 2.0, @uref{http://www.openacc.org/}). +Note that this is an experimental feature, incomplete, and subject to +change in future versions of GCC. See +@uref{https://gcc.gnu.org/wiki/OpenACC} for more information. @node Varying Length Character Strings @subsection Varying Length Character Strings @@ -963,7 +972,8 @@ module. @cindex statement, @code{ISO_FORTRAN_ENV} @code{USE} statement with @code{INTRINSIC} and @code{NON_INTRINSIC} attribute; supported intrinsic modules: @code{ISO_FORTRAN_ENV}, -@code{ISO_C_BINDING}, @code{OMP_LIB} and @code{OMP_LIB_KINDS}. +@code{ISO_C_BINDING}, @code{OMP_LIB} and @code{OMP_LIB_KINDS}, +and @code{OPENACC}. @item Renaming of operators in the @code{USE} statement. @@ -1375,6 +1385,7 @@ without warning. * Cray pointers:: * CONVERT specifier:: * OpenMP:: +* OpenACC:: * Argument list functions:: @end menu @@ -1949,6 +1960,37 @@ to the command line. However, this is not supported by @command{gcc} and thus not recommended. @end itemize +@node OpenACC +@subsection OpenACC +@cindex OpenACC + +OpenACC is an application programming interface (API) that supports +offloading of code to accelerator devices. It consists of a set of +compiler directives, library routines, and environment variables that +influence run-time behavior. + +GNU Fortran strives to be compatible to the +@uref{http://www.openacc.org/, OpenACC Application Programming +Interface v2.0}. + +To enable the processing of the OpenACC directive @code{!$acc} in +free-form source code; the @code{c$acc}, @code{*$acc} and @code{!$acc} +directives in fixed form; the @code{!$} conditional compilation +sentinels in free form; and the @code{c$}, @code{*$} and @code{!$} +sentinels in fixed form, @command{gfortran} needs to be invoked with +the @option{-fopenacc}. This also arranges for automatic linking of +the GNU Offloading and Multi Processing Runtime Library +@ref{Top,,libgomp,libgomp,GNU Offloading and Multi Processing Runtime +Library}. + +The OpenACC Fortran runtime library routines are provided both in a +form of a Fortran 90 module named @code{openacc} and in a form of a +Fortran @code{include} file named @file{openacc_lib.h}. + +Note that this is an experimental feature, incomplete, and subject to +change in future versions of GCC. See +@uref{https://gcc.gnu.org/wiki/OpenACC} for more information. + @node Argument list functions @subsection Argument list functions @code{%VAL}, @code{%REF} and @code{%LOC} @cindex argument list functions diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index 36c70d9..06bce15 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -13774,6 +13774,7 @@ Fortran 95 elemental function: @ref{IEOR} * ISO_C_BINDING:: * IEEE modules:: * OpenMP Modules OMP_LIB and OMP_LIB_KINDS:: +* OpenACC Module OPENACC:: @end menu @node ISO_FORTRAN_ENV @@ -14018,6 +14019,7 @@ with the following options: @code{-fno-unsafe-math-optimizations -frounding-math -fsignaling-nans}. + @node OpenMP Modules OMP_LIB and OMP_LIB_KINDS @section OpenMP Modules @code{OMP_LIB} and @code{OMP_LIB_KINDS} @table @asis @@ -14074,3 +14076,30 @@ kind @code{omp_proc_bind_kind}: @item @code{omp_proc_bind_close} @item @code{omp_proc_bind_spread} @end table + + + +@node OpenACC Module OPENACC +@section OpenACC Module @code{OPENACC} +@table @asis +@item @emph{Standard}: +OpenACC Application Programming Interface v2.0 +@end table + + +The OpenACC Fortran runtime library routines are provided both in a +form of a Fortran 90 module, named @code{OPENACC}, and in form of a +Fortran @code{include} file named @file{openacc_lib.h}. The +procedures provided by @code{OPENACC} can be found in the +@ref{Top,,Introduction,libgomp,GNU Offloading and Multi Processing +Runtime Library} manual, the named constants defined in the modules +are listed below. + +For details refer to the actual +@uref{http://www.openacc.org/, +OpenACC Application Programming Interface v2.0}. + +@code{OPENACC} provides the scalar default-integer +named constant @code{openacc_version} with a value of the form +@var{yyyymm}, where @code{yyyy} is the year and @var{mm} the month +of the OpenACC version; for OpenACC v2.0 the value is @code{201306}. diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi index 39bc479..9228c78 100644 --- a/gcc/fortran/invoke.texi +++ b/gcc/fortran/invoke.texi @@ -120,7 +120,7 @@ by type. Explanations are in the following sections. -ffixed-line-length-none -ffree-form -ffree-line-length-@var{n} @gol -ffree-line-length-none -fimplicit-none -finteger-4-integer-8 @gol -fmax-identifier-length -fmodule-private -fno-fixed-form -fno-range-check @gol --fopenmp -freal-4-real-10 -freal-4-real-16 -freal-4-real-8 @gol +-fopenacc -fopenmp -freal-4-real-10 -freal-4-real-16 -freal-4-real-8 @gol -freal-8-real-10 -freal-8-real-16 -freal-8-real-4 -std=@var{std} } @@ -302,6 +302,20 @@ Specify that no implicit typing is allowed, unless overridden by explicit Enable the Cray pointer extension, which provides C-like pointer functionality. +@item -fopenacc +@opindex @code{fopenacc} +@cindex OpenACC +Enable the OpenACC extensions. This includes OpenACC @code{!$acc} +directives in free form and @code{c$acc}, @code{*$acc} and +@code{!$acc} directives in fixed form, @code{!$} conditional +compilation sentinels in free form and @code{c$}, @code{*$} and +@code{!$} sentinels in fixed form, and when linking arranges for the +OpenACC runtime library to be linked in. + +Note that this is an experimental feature, incomplete, and subject to +change in future versions of GCC. See +@w{@uref{https://gcc.gnu.org/wiki/OpenACC}} for more information. + @item -fopenmp @opindex @code{fopenmp} @cindex OpenMP diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt index 530ec97..a7a4ed6 100644 --- a/gcc/fortran/lang.opt +++ b/gcc/fortran/lang.opt @@ -566,6 +566,10 @@ fmodule-private Fortran Var(flag_module_private) Set default accessibility of module entities to PRIVATE. +fopenacc +Fortran +; Documented in C + fopenmp Fortran ; Documented in C diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index 2973d5a..8234c27 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -2501,7 +2501,9 @@ match_exit_cycle (gfc_statement st, gfc_exec_op op) if (o != NULL) { - gfc_error ("%s statement at %C leaving OpenMP structured block", + gfc_error (is_oacc (p) + ? "%s statement at %C leaving OpenACC structured block" + : "%s statement at %C leaving OpenMP structured block", gfc_ascii_statement (st)); return MATCH_ERROR; } @@ -2511,6 +2513,33 @@ match_exit_cycle (gfc_statement st, gfc_exec_op op) if (cnt > 0 && o != NULL && o->state == COMP_OMP_STRUCTURED_BLOCK + && (o->head->op == EXEC_OACC_LOOP + || o->head->op == EXEC_OACC_PARALLEL_LOOP)) + { + int collapse = 1; + gcc_assert (o->head->next != NULL + && (o->head->next->op == EXEC_DO + || o->head->next->op == EXEC_DO_WHILE) + && o->previous != NULL + && o->previous->tail->op == o->head->op); + if (o->previous->tail->ext.omp_clauses != NULL + && o->previous->tail->ext.omp_clauses->collapse > 1) + collapse = o->previous->tail->ext.omp_clauses->collapse; + if (st == ST_EXIT && cnt <= collapse) + { + gfc_error ("EXIT statement at %C terminating !$ACC LOOP loop"); + return MATCH_ERROR; + } + if (st == ST_CYCLE && cnt < collapse) + { + gfc_error ("CYCLE statement at %C to non-innermost collapsed" + " !$ACC LOOP loop"); + return MATCH_ERROR; + } + } + if (cnt > 0 + && o != NULL + && (o->state == COMP_OMP_STRUCTURED_BLOCK) && (o->head->op == EXEC_OMP_DO || o->head->op == EXEC_OMP_PARALLEL_DO || o->head->op == EXEC_OMP_SIMD diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index 3b49ccd..96d3ec1 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -122,6 +122,22 @@ gfc_common_head *gfc_get_common (const char *, int); /* openmp.c. */ +/* OpenACC directive matchers. */ +match gfc_match_oacc_cache (void); +match gfc_match_oacc_wait (void); +match gfc_match_oacc_update (void); +match gfc_match_oacc_declare (void); +match gfc_match_oacc_loop (void); +match gfc_match_oacc_host_data (void); +match gfc_match_oacc_data (void); +match gfc_match_oacc_kernels (void); +match gfc_match_oacc_kernels_loop (void); +match gfc_match_oacc_parallel (void); +match gfc_match_oacc_parallel_loop (void); +match gfc_match_oacc_enter_data (void); +match gfc_match_oacc_exit_data (void); +match gfc_match_oacc_routine (void); + /* OpenMP directive matchers. */ match gfc_match_omp_eos (void); match gfc_match_omp_atomic (void); diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 65659c0..005739b 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -27,6 +27,8 @@ along with GCC; see the file COPYING3. If not see #include "match.h" #include "parse.h" #include "hash-set.h" +#include "diagnostic.h" +#include "gomp-constants.h" /* Match an end of OpenMP directive. End of OpenMP directive is optional whitespace, followed by '\n' or comment '!'. */ @@ -76,11 +78,33 @@ gfc_free_omp_clauses (gfc_omp_clauses *c) gfc_free_expr (c->device); gfc_free_expr (c->thread_limit); gfc_free_expr (c->dist_chunk_size); + gfc_free_expr (c->async_expr); + gfc_free_expr (c->gang_expr); + gfc_free_expr (c->worker_expr); + gfc_free_expr (c->vector_expr); + gfc_free_expr (c->num_gangs_expr); + gfc_free_expr (c->num_workers_expr); + gfc_free_expr (c->vector_length_expr); for (i = 0; i < OMP_LIST_NUM; i++) gfc_free_omp_namelist (c->lists[i]); + gfc_free_expr_list (c->wait_list); + gfc_free_expr_list (c->tile_list); free (c); } +/* Free expression list. */ +void +gfc_free_expr_list (gfc_expr_list *list) +{ + gfc_expr_list *n; + + for (; list; list = n) + { + n = list->next; + free (list); + } +} + /* Free an !$omp declare simd construct list. */ void @@ -287,45 +311,175 @@ cleanup: return MATCH_ERROR; } -#define OMP_CLAUSE_PRIVATE (1U << 0) -#define OMP_CLAUSE_FIRSTPRIVATE (1U << 1) -#define OMP_CLAUSE_LASTPRIVATE (1U << 2) -#define OMP_CLAUSE_COPYPRIVATE (1U << 3) -#define OMP_CLAUSE_SHARED (1U << 4) -#define OMP_CLAUSE_COPYIN (1U << 5) -#define OMP_CLAUSE_REDUCTION (1U << 6) -#define OMP_CLAUSE_IF (1U << 7) -#define OMP_CLAUSE_NUM_THREADS (1U << 8) -#define OMP_CLAUSE_SCHEDULE (1U << 9) -#define OMP_CLAUSE_DEFAULT (1U << 10) -#define OMP_CLAUSE_ORDERED (1U << 11) -#define OMP_CLAUSE_COLLAPSE (1U << 12) -#define OMP_CLAUSE_UNTIED (1U << 13) -#define OMP_CLAUSE_FINAL (1U << 14) -#define OMP_CLAUSE_MERGEABLE (1U << 15) -#define OMP_CLAUSE_ALIGNED (1U << 16) -#define OMP_CLAUSE_DEPEND (1U << 17) -#define OMP_CLAUSE_INBRANCH (1U << 18) -#define OMP_CLAUSE_LINEAR (1U << 19) -#define OMP_CLAUSE_NOTINBRANCH (1U << 20) -#define OMP_CLAUSE_PROC_BIND (1U << 21) -#define OMP_CLAUSE_SAFELEN (1U << 22) -#define OMP_CLAUSE_SIMDLEN (1U << 23) -#define OMP_CLAUSE_UNIFORM (1U << 24) -#define OMP_CLAUSE_DEVICE (1U << 25) -#define OMP_CLAUSE_MAP (1U << 26) -#define OMP_CLAUSE_TO (1U << 27) -#define OMP_CLAUSE_FROM (1U << 28) -#define OMP_CLAUSE_NUM_TEAMS (1U << 29) -#define OMP_CLAUSE_THREAD_LIMIT (1U << 30) -#define OMP_CLAUSE_DIST_SCHEDULE (1U << 31) - -/* Match OpenMP directive clauses. MASK is a bitmask of +static match +match_oacc_expr_list (const char *str, gfc_expr_list **list, + bool allow_asterisk) +{ + gfc_expr_list *head, *tail, *p; + locus old_loc; + gfc_expr *expr; + match m; + + head = tail = NULL; + + old_loc = gfc_current_locus; + + m = gfc_match (str); + if (m != MATCH_YES) + return m; + + for (;;) + { + m = gfc_match_expr (&expr); + if (m == MATCH_YES || allow_asterisk) + { + p = gfc_get_expr_list (); + if (head == NULL) + head = tail = p; + else + { + tail->next = p; + tail = tail->next; + } + if (m == MATCH_YES) + tail->expr = expr; + else if (gfc_match (" *") != MATCH_YES) + goto syntax; + goto next_item; + } + if (m == MATCH_ERROR) + goto cleanup; + goto syntax; + + next_item: + if (gfc_match_char (')') == MATCH_YES) + break; + if (gfc_match_char (',') != MATCH_YES) + goto syntax; + } + + while (*list) + list = &(*list)->next; + + *list = head; + return MATCH_YES; + +syntax: + gfc_error ("Syntax error in OpenACC expression list at %C"); + +cleanup: + gfc_free_expr_list (head); + gfc_current_locus = old_loc; + return MATCH_ERROR; +} + +static match +match_oacc_clause_gang (gfc_omp_clauses *cp) +{ + if (gfc_match_char ('(') != MATCH_YES) + return MATCH_NO; + if (gfc_match (" num :") == MATCH_YES) + { + cp->gang_static = false; + return gfc_match (" %e )", &cp->gang_expr); + } + if (gfc_match (" static :") == MATCH_YES) + { + cp->gang_static = true; + if (gfc_match (" * )") != MATCH_YES) + return gfc_match (" %e )", &cp->gang_expr); + return MATCH_YES; + } + return gfc_match (" %e )", &cp->gang_expr); +} + +#define OMP_CLAUSE_PRIVATE ((uint64_t) 1 << 0) +#define OMP_CLAUSE_FIRSTPRIVATE ((uint64_t) 1 << 1) +#define OMP_CLAUSE_LASTPRIVATE ((uint64_t) 1 << 2) +#define OMP_CLAUSE_COPYPRIVATE ((uint64_t) 1 << 3) +#define OMP_CLAUSE_SHARED ((uint64_t) 1 << 4) +#define OMP_CLAUSE_COPYIN ((uint64_t) 1 << 5) +#define OMP_CLAUSE_REDUCTION ((uint64_t) 1 << 6) +#define OMP_CLAUSE_IF ((uint64_t) 1 << 7) +#define OMP_CLAUSE_NUM_THREADS ((uint64_t) 1 << 8) +#define OMP_CLAUSE_SCHEDULE ((uint64_t) 1 << 9) +#define OMP_CLAUSE_DEFAULT ((uint64_t) 1 << 10) +#define OMP_CLAUSE_ORDERED ((uint64_t) 1 << 11) +#define OMP_CLAUSE_COLLAPSE ((uint64_t) 1 << 12) +#define OMP_CLAUSE_UNTIED ((uint64_t) 1 << 13) +#define OMP_CLAUSE_FINAL ((uint64_t) 1 << 14) +#define OMP_CLAUSE_MERGEABLE ((uint64_t) 1 << 15) +#define OMP_CLAUSE_ALIGNED ((uint64_t) 1 << 16) +#define OMP_CLAUSE_DEPEND ((uint64_t) 1 << 17) +#define OMP_CLAUSE_INBRANCH ((uint64_t) 1 << 18) +#define OMP_CLAUSE_LINEAR ((uint64_t) 1 << 19) +#define OMP_CLAUSE_NOTINBRANCH ((uint64_t) 1 << 20) +#define OMP_CLAUSE_PROC_BIND ((uint64_t) 1 << 21) +#define OMP_CLAUSE_SAFELEN ((uint64_t) 1 << 22) +#define OMP_CLAUSE_SIMDLEN ((uint64_t) 1 << 23) +#define OMP_CLAUSE_UNIFORM ((uint64_t) 1 << 24) +#define OMP_CLAUSE_DEVICE ((uint64_t) 1 << 25) +#define OMP_CLAUSE_MAP ((uint64_t) 1 << 26) +#define OMP_CLAUSE_TO ((uint64_t) 1 << 27) +#define OMP_CLAUSE_FROM ((uint64_t) 1 << 28) +#define OMP_CLAUSE_NUM_TEAMS ((uint64_t) 1 << 29) +#define OMP_CLAUSE_THREAD_LIMIT ((uint64_t) 1 << 30) +#define OMP_CLAUSE_DIST_SCHEDULE ((uint64_t) 1 << 31) + +/* OpenACC 2.0 clauses. */ +#define OMP_CLAUSE_ASYNC ((uint64_t) 1 << 32) +#define OMP_CLAUSE_NUM_GANGS ((uint64_t) 1 << 33) +#define OMP_CLAUSE_NUM_WORKERS ((uint64_t) 1 << 34) +#define OMP_CLAUSE_VECTOR_LENGTH ((uint64_t) 1 << 35) +#define OMP_CLAUSE_COPY ((uint64_t) 1 << 36) +#define OMP_CLAUSE_COPYOUT ((uint64_t) 1 << 37) +#define OMP_CLAUSE_CREATE ((uint64_t) 1 << 38) +#define OMP_CLAUSE_PRESENT ((uint64_t) 1 << 39) +#define OMP_CLAUSE_PRESENT_OR_COPY ((uint64_t) 1 << 40) +#define OMP_CLAUSE_PRESENT_OR_COPYIN ((uint64_t) 1 << 41) +#define OMP_CLAUSE_PRESENT_OR_COPYOUT ((uint64_t) 1 << 42) +#define OMP_CLAUSE_PRESENT_OR_CREATE ((uint64_t) 1 << 43) +#define OMP_CLAUSE_DEVICEPTR ((uint64_t) 1 << 44) +#define OMP_CLAUSE_GANG ((uint64_t) 1 << 45) +#define OMP_CLAUSE_WORKER ((uint64_t) 1 << 46) +#define OMP_CLAUSE_VECTOR ((uint64_t) 1 << 47) +#define OMP_CLAUSE_SEQ ((uint64_t) 1 << 48) +#define OMP_CLAUSE_INDEPENDENT ((uint64_t) 1 << 49) +#define OMP_CLAUSE_USE_DEVICE ((uint64_t) 1 << 50) +#define OMP_CLAUSE_DEVICE_RESIDENT ((uint64_t) 1 << 51) +#define OMP_CLAUSE_HOST_SELF ((uint64_t) 1 << 52) +#define OMP_CLAUSE_OACC_DEVICE ((uint64_t) 1 << 53) +#define OMP_CLAUSE_WAIT ((uint64_t) 1 << 54) +#define OMP_CLAUSE_DELETE ((uint64_t) 1 << 55) +#define OMP_CLAUSE_AUTO ((uint64_t) 1 << 56) +#define OMP_CLAUSE_TILE ((uint64_t) 1 << 57) + +/* Helper function for OpenACC and OpenMP clauses involving memory + mapping. */ + +static bool +gfc_match_omp_map_clause (gfc_omp_namelist **list, gfc_omp_map_op map_op) +{ + gfc_omp_namelist **head = NULL; + if (gfc_match_omp_variable_list ("", list, false, NULL, &head, true) + == MATCH_YES) + { + gfc_omp_namelist *n; + for (n = *head; n; n = n->next) + n->u.map_op = map_op; + return true; + } + + return false; +} + +/* Match OpenMP and OpenACC directive clauses. MASK is a bitmask of clauses that are allowed for a particular directive. */ static match -gfc_match_omp_clauses (gfc_omp_clauses **cp, unsigned int mask, - bool first = true, bool needs_space = true) +gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, + bool first = true, bool needs_space = true, + bool openacc = false) { gfc_omp_clauses *c = gfc_get_omp_clauses (); locus old_loc; @@ -339,6 +493,56 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, unsigned int mask, needs_space = false; first = false; gfc_gobble_whitespace (); + if ((mask & OMP_CLAUSE_ASYNC) && !c->async) + if (gfc_match ("async") == MATCH_YES) + { + c->async = true; + needs_space = false; + if (gfc_match (" ( %e )", &c->async_expr) != MATCH_YES) + { + c->async_expr = gfc_get_constant_expr (BT_INTEGER, + gfc_default_integer_kind, + &gfc_current_locus); + mpz_set_si (c->async_expr->value.integer, GOMP_ASYNC_NOVAL); + } + continue; + } + if ((mask & OMP_CLAUSE_GANG) && !c->gang) + if (gfc_match ("gang") == MATCH_YES) + { + c->gang = true; + if (match_oacc_clause_gang(c) == MATCH_YES) + needs_space = false; + else + needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_WORKER) && !c->worker) + if (gfc_match ("worker") == MATCH_YES) + { + c->worker = true; + if (gfc_match (" ( num : %e )", &c->worker_expr) == MATCH_YES + || gfc_match (" ( %e )", &c->worker_expr) == MATCH_YES) + needs_space = false; + else + needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_VECTOR_LENGTH) && c->vector_length_expr == NULL + && gfc_match ("vector_length ( %e )", &c->vector_length_expr) + == MATCH_YES) + continue; + if ((mask & OMP_CLAUSE_VECTOR) && !c->vector) + if (gfc_match ("vector") == MATCH_YES) + { + c->vector = true; + if (gfc_match (" ( length : %e )", &c->vector_expr) == MATCH_YES + || gfc_match (" ( %e )", &c->vector_expr) == MATCH_YES) + needs_space = false; + else + needs_space = true; + continue; + } if ((mask & OMP_CLAUSE_IF) && c->if_expr == NULL && gfc_match ("if ( %e )", &c->if_expr) == MATCH_YES) continue; @@ -376,11 +580,159 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, unsigned int mask, &c->lists[OMP_LIST_SHARED], true) == MATCH_YES) continue; - if ((mask & OMP_CLAUSE_COPYIN) - && gfc_match_omp_variable_list ("copyin (", - &c->lists[OMP_LIST_COPYIN], true) + if (mask & OMP_CLAUSE_COPYIN) + { + if (openacc) + { + if (gfc_match ("copyin ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_TO)) + continue; + } + else if (gfc_match_omp_variable_list ("copyin (", + &c->lists[OMP_LIST_COPYIN], + true) == MATCH_YES) + continue; + } + if ((mask & OMP_CLAUSE_NUM_GANGS) && c->num_gangs_expr == NULL + && gfc_match ("num_gangs ( %e )", &c->num_gangs_expr) == MATCH_YES) + continue; + if ((mask & OMP_CLAUSE_NUM_WORKERS) && c->num_workers_expr == NULL + && gfc_match ("num_workers ( %e )", &c->num_workers_expr) + == MATCH_YES) + continue; + if ((mask & OMP_CLAUSE_COPY) + && gfc_match ("copy ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_TOFROM)) + continue; + if ((mask & OMP_CLAUSE_COPYOUT) + && gfc_match ("copyout ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_FROM)) + continue; + if ((mask & OMP_CLAUSE_CREATE) + && gfc_match ("create ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_ALLOC)) + continue; + if ((mask & OMP_CLAUSE_DELETE) + && gfc_match ("delete ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_DEALLOC)) + continue; + if ((mask & OMP_CLAUSE_PRESENT) + && gfc_match ("present ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_PRESENT)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_COPY) + && gfc_match ("present_or_copy ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_TOFROM)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_COPY) + && gfc_match ("pcopy ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_TOFROM)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_COPYIN) + && gfc_match ("present_or_copyin ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_TO)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_COPYIN) + && gfc_match ("pcopyin ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_TO)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_COPYOUT) + && gfc_match ("present_or_copyout ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FROM)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_COPYOUT) + && gfc_match ("pcopyout ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FROM)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_CREATE) + && gfc_match ("present_or_create ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_ALLOC)) + continue; + if ((mask & OMP_CLAUSE_PRESENT_OR_CREATE) + && gfc_match ("pcreate ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_ALLOC)) + continue; + if ((mask & OMP_CLAUSE_DEVICEPTR) + && gfc_match ("deviceptr ( ") == MATCH_YES) + { + gfc_omp_namelist **list = &c->lists[OMP_LIST_MAP]; + gfc_omp_namelist **head = NULL; + if (gfc_match_omp_variable_list ("", list, true, NULL, &head, false) + == MATCH_YES) + { + gfc_omp_namelist *n; + for (n = *head; n; n = n->next) + n->u.map_op = OMP_MAP_FORCE_DEVICEPTR; + continue; + } + } + if ((mask & OMP_CLAUSE_USE_DEVICE) + && gfc_match_omp_variable_list ("use_device (", + &c->lists[OMP_LIST_USE_DEVICE], true) + == MATCH_YES) + continue; + if ((mask & OMP_CLAUSE_DEVICE_RESIDENT) + && gfc_match_omp_variable_list ("device_resident (", + &c->lists[OMP_LIST_DEVICE_RESIDENT], + true) == MATCH_YES) continue; + if ((mask & OMP_CLAUSE_OACC_DEVICE) + && gfc_match ("device ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_TO)) + continue; + if ((mask & OMP_CLAUSE_HOST_SELF) + && (gfc_match ("host ( ") == MATCH_YES + || gfc_match ("self ( ") == MATCH_YES) + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_FORCE_FROM)) + continue; + if ((mask & OMP_CLAUSE_TILE) + && match_oacc_expr_list ("tile (", &c->tile_list, true) == MATCH_YES) + continue; + if ((mask & OMP_CLAUSE_SEQ) && !c->seq + && gfc_match ("seq") == MATCH_YES) + { + c->seq = true; + needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_INDEPENDENT) && !c->independent + && gfc_match ("independent") == MATCH_YES) + { + c->independent = true; + needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_AUTO) && !c->par_auto + && gfc_match ("auto") == MATCH_YES) + { + c->par_auto = true; + needs_space = true; + continue; + } + if ((mask & OMP_CLAUSE_WAIT) && !c->wait + && gfc_match ("wait") == MATCH_YES) + { + c->wait = true; + match_oacc_expr_list (" (", &c->wait_list, false); + continue; + } old_loc = gfc_current_locus; if ((mask & OMP_CLAUSE_REDUCTION) && gfc_match ("reduction ( ") == MATCH_YES) @@ -785,6 +1137,352 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, unsigned int mask, return MATCH_YES; } + +#define OACC_PARALLEL_CLAUSES \ + (OMP_CLAUSE_IF | OMP_CLAUSE_ASYNC | OMP_CLAUSE_NUM_GANGS \ + | OMP_CLAUSE_NUM_WORKERS | OMP_CLAUSE_VECTOR_LENGTH | OMP_CLAUSE_REDUCTION \ + | OMP_CLAUSE_COPY | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT \ + | OMP_CLAUSE_CREATE | OMP_CLAUSE_PRESENT | OMP_CLAUSE_PRESENT_OR_COPY \ + | OMP_CLAUSE_PRESENT_OR_COPYIN | OMP_CLAUSE_PRESENT_OR_COPYOUT \ + | OMP_CLAUSE_PRESENT_OR_CREATE | OMP_CLAUSE_DEVICEPTR | OMP_CLAUSE_PRIVATE \ + | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_WAIT) +#define OACC_KERNELS_CLAUSES \ + (OMP_CLAUSE_IF | OMP_CLAUSE_ASYNC | OMP_CLAUSE_DEVICEPTR \ + | OMP_CLAUSE_COPY | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT \ + | OMP_CLAUSE_CREATE | OMP_CLAUSE_PRESENT | OMP_CLAUSE_PRESENT_OR_COPY \ + | OMP_CLAUSE_PRESENT_OR_COPYIN | OMP_CLAUSE_PRESENT_OR_COPYOUT \ + | OMP_CLAUSE_PRESENT_OR_CREATE | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_WAIT) +#define OACC_DATA_CLAUSES \ + (OMP_CLAUSE_IF | OMP_CLAUSE_DEVICEPTR | OMP_CLAUSE_COPY \ + | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT | OMP_CLAUSE_CREATE \ + | OMP_CLAUSE_PRESENT | OMP_CLAUSE_PRESENT_OR_COPY \ + | OMP_CLAUSE_PRESENT_OR_COPYIN | OMP_CLAUSE_PRESENT_OR_COPYOUT \ + | OMP_CLAUSE_PRESENT_OR_CREATE) +#define OACC_LOOP_CLAUSES \ + (OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_GANG | OMP_CLAUSE_WORKER \ + | OMP_CLAUSE_VECTOR | OMP_CLAUSE_SEQ | OMP_CLAUSE_INDEPENDENT \ + | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_AUTO \ + | OMP_CLAUSE_TILE) +#define OACC_PARALLEL_LOOP_CLAUSES \ + (OACC_LOOP_CLAUSES | OACC_PARALLEL_CLAUSES) +#define OACC_KERNELS_LOOP_CLAUSES \ + (OACC_LOOP_CLAUSES | OACC_KERNELS_CLAUSES) +#define OACC_HOST_DATA_CLAUSES OMP_CLAUSE_USE_DEVICE +#define OACC_DECLARE_CLAUSES \ + (OMP_CLAUSE_COPY | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT \ + | OMP_CLAUSE_CREATE | OMP_CLAUSE_DEVICEPTR | OMP_CLAUSE_DEVICE_RESIDENT \ + | OMP_CLAUSE_PRESENT | OMP_CLAUSE_PRESENT_OR_COPY \ + | OMP_CLAUSE_PRESENT_OR_COPYIN | OMP_CLAUSE_PRESENT_OR_COPYOUT \ + | OMP_CLAUSE_PRESENT_OR_CREATE) +#define OACC_UPDATE_CLAUSES \ + (OMP_CLAUSE_IF | OMP_CLAUSE_ASYNC | OMP_CLAUSE_HOST_SELF \ + | OMP_CLAUSE_OACC_DEVICE | OMP_CLAUSE_WAIT) +#define OACC_ENTER_DATA_CLAUSES \ + (OMP_CLAUSE_IF | OMP_CLAUSE_ASYNC | OMP_CLAUSE_WAIT | OMP_CLAUSE_COPYIN \ + | OMP_CLAUSE_CREATE | OMP_CLAUSE_PRESENT_OR_COPYIN \ + | OMP_CLAUSE_PRESENT_OR_CREATE) +#define OACC_EXIT_DATA_CLAUSES \ + (OMP_CLAUSE_IF | OMP_CLAUSE_ASYNC | OMP_CLAUSE_WAIT | OMP_CLAUSE_COPYOUT \ + | OMP_CLAUSE_DELETE) +#define OACC_WAIT_CLAUSES \ + (OMP_CLAUSE_ASYNC) + + +match +gfc_match_oacc_parallel_loop (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_PARALLEL_LOOP_CLAUSES, false, false, + true) != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_PARALLEL_LOOP; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_parallel (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_PARALLEL_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_PARALLEL; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_kernels_loop (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_KERNELS_LOOP_CLAUSES, false, false, + true) != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_KERNELS_LOOP; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_kernels (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_KERNELS_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_KERNELS; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_data (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_DATA_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_DATA; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_host_data (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_HOST_DATA_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_HOST_DATA; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_loop (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_LOOP_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_LOOP; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_declare (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_DECLARE_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.ext.omp_clauses = c; + new_st.ext.omp_clauses->loc = gfc_current_locus; + return MATCH_YES; +} + + +match +gfc_match_oacc_update (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_UPDATE_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_UPDATE; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_enter_data (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_ENTER_DATA_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_ENTER_DATA; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_exit_data (void) +{ + gfc_omp_clauses *c; + if (gfc_match_omp_clauses (&c, OACC_EXIT_DATA_CLAUSES, false, false, true) + != MATCH_YES) + return MATCH_ERROR; + + new_st.op = EXEC_OACC_EXIT_DATA; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_wait (void) +{ + gfc_omp_clauses *c = gfc_get_omp_clauses (); + gfc_expr_list *wait_list = NULL, *el; + + match_oacc_expr_list (" (", &wait_list, true); + gfc_match_omp_clauses (&c, OACC_WAIT_CLAUSES, false, false, true); + + if (gfc_match_omp_eos () != MATCH_YES) + { + gfc_error ("Unexpected junk in !$ACC WAIT at %C"); + return MATCH_ERROR; + } + + if (wait_list) + for (el = wait_list; el; el = el->next) + { + if (el->expr == NULL) + { + gfc_error ("Invalid argument to $!ACC WAIT at %L", + &wait_list->expr->where); + return MATCH_ERROR; + } + + if (!gfc_resolve_expr (el->expr) + || el->expr->ts.type != BT_INTEGER || el->expr->rank != 0 + || el->expr->expr_type != EXPR_CONSTANT) + { + gfc_error ("WAIT clause at %L requires a scalar INTEGER expression", + &el->expr->where); + + return MATCH_ERROR; + } + } + c->wait_list = wait_list; + new_st.op = EXEC_OACC_WAIT; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_cache (void) +{ + gfc_omp_clauses *c = gfc_get_omp_clauses (); + match m = gfc_match_omp_variable_list (" (", + &c->lists[OMP_LIST_CACHE], true); + if (m != MATCH_YES) + { + gfc_free_omp_clauses(c); + return m; + } + + if (gfc_current_state() != COMP_DO + && gfc_current_state() != COMP_DO_CONCURRENT) + { + gfc_error ("ACC CACHE directive must be inside of loop %C"); + gfc_free_omp_clauses(c); + return MATCH_ERROR; + } + + new_st.op = EXEC_OACC_CACHE; + new_st.ext.omp_clauses = c; + return MATCH_YES; +} + + +match +gfc_match_oacc_routine (void) +{ + locus old_loc; + gfc_symbol *sym; + match m; + + old_loc = gfc_current_locus; + + m = gfc_match (" ("); + + if (gfc_current_ns->proc_name + && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY + && m == MATCH_YES) + { + gfc_error ("Only the !$ACC ROUTINE form without " + "list is allowed in interface block at %C"); + goto cleanup; + } + + if (m == MATCH_NO + && gfc_current_ns->proc_name + && gfc_match_omp_eos () == MATCH_YES) + { + if (!gfc_add_omp_declare_target (&gfc_current_ns->proc_name->attr, + gfc_current_ns->proc_name->name, + &old_loc)) + goto cleanup; + return MATCH_YES; + } + + if (m != MATCH_YES) + return m; + + /* Scan for a function name. */ + m = gfc_match_symbol (&sym, 0); + + if (m != MATCH_YES) + { + gfc_error ("Syntax error in !$ACC ROUTINE ( NAME ) at %C"); + gfc_current_locus = old_loc; + return MATCH_ERROR; + } + + if (!sym->attr.external && !sym->attr.function && !sym->attr.subroutine) + { + gfc_error ("Syntax error in !$ACC ROUTINE ( NAME ) at %C, invalid" + " function name '%s'", sym->name); + gfc_current_locus = old_loc; + return MATCH_ERROR; + } + + if (gfc_match_char (')') != MATCH_YES) + { + gfc_error ("Syntax error in !$ACC ROUTINE ( NAME ) at %C, expecting" + " ')' after NAME"); + gfc_current_locus = old_loc; + return MATCH_ERROR; + } + + if (gfc_match_omp_eos () != MATCH_YES) + { + gfc_error ("Unexpected junk after !$ACC ROUTINE at %C"); + goto cleanup; + } + return MATCH_YES; + +cleanup: + gfc_current_locus = old_loc; + return MATCH_ERROR; +} + + #define OMP_PARALLEL_CLAUSES \ (OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_SHARED \ | OMP_CLAUSE_COPYIN | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_IF \ @@ -1916,6 +2614,129 @@ gfc_match_omp_end_single (void) } +static bool +oacc_is_loop (gfc_code *code) +{ + return code->op == EXEC_OACC_PARALLEL_LOOP + || code->op == EXEC_OACC_KERNELS_LOOP + || code->op == EXEC_OACC_LOOP; +} + +static void +resolve_oacc_scalar_int_expr (gfc_expr *expr, const char *clause) +{ + if (!gfc_resolve_expr (expr) + || expr->ts.type != BT_INTEGER || expr->rank != 0) + gfc_error ("%s clause at %L requires a scalar INTEGER expression", + clause, &expr->where); +} + + +static void +resolve_oacc_positive_int_expr (gfc_expr *expr, const char *clause) +{ + resolve_oacc_scalar_int_expr (expr, clause); + if (expr->expr_type == EXPR_CONSTANT && expr->ts.type == BT_INTEGER + && mpz_sgn(expr->value.integer) <= 0) + gfc_warning ("INTEGER expression of %s clause at %L must be positive", + clause, &expr->where); +} + +/* Emits error when symbol is pointer, cray pointer or cray pointee + of derived of polymorphic type. */ + +static void +check_symbol_not_pointer (gfc_symbol *sym, locus loc, const char *name) +{ + if (sym->ts.type == BT_DERIVED && sym->attr.pointer) + gfc_error ("POINTER object '%s' of derived type in %s clause at %L", + sym->name, name, &loc); + if (sym->ts.type == BT_DERIVED && sym->attr.cray_pointer) + gfc_error ("Cray pointer object of derived type '%s' in %s clause at %L", + sym->name, name, &loc); + if (sym->ts.type == BT_DERIVED && sym->attr.cray_pointee) + gfc_error ("Cray pointee object of derived type '%s' in %s clause at %L", + sym->name, name, &loc); + + if ((sym->ts.type == BT_ASSUMED && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.pointer)) + gfc_error ("POINTER object '%s' of polymorphic type in %s clause at %L", + sym->name, name, &loc); + if ((sym->ts.type == BT_ASSUMED && sym->attr.cray_pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.cray_pointer)) + gfc_error ("Cray pointer object of polymorphic type '%s' in %s clause at %L", + sym->name, name, &loc); + if ((sym->ts.type == BT_ASSUMED && sym->attr.cray_pointee) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.cray_pointee)) + gfc_error ("Cray pointee object of polymorphic type '%s' in %s clause at %L", + sym->name, name, &loc); +} + +/* Emits error when symbol represents assumed size/rank array. */ + +static void +check_array_not_assumed (gfc_symbol *sym, locus loc, const char *name) +{ + if (sym->as && sym->as->type == AS_ASSUMED_SIZE) + gfc_error ("Assumed size array '%s' in %s clause at %L", + sym->name, name, &loc); + if (sym->as && sym->as->type == AS_ASSUMED_RANK) + gfc_error ("Assumed rank array '%s' in %s clause at %L", + sym->name, name, &loc); + if (sym->as && sym->as->type == AS_DEFERRED && sym->attr.pointer + && !sym->attr.contiguous) + gfc_error ("Noncontiguous deferred shape array '%s' in %s clause at %L", + sym->name, name, &loc); +} + +static void +resolve_oacc_data_clauses (gfc_symbol *sym, locus loc, const char *name) +{ + if (sym->ts.type == BT_DERIVED && sym->attr.allocatable) + gfc_error ("ALLOCATABLE object '%s' of derived type in %s clause at %L", + sym->name, name, &loc); + if ((sym->ts.type == BT_ASSUMED && sym->attr.allocatable) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.allocatable)) + gfc_error ("ALLOCATABLE object '%s' of polymorphic type " + "in %s clause at %L", sym->name, name, &loc); + check_symbol_not_pointer (sym, loc, name); + check_array_not_assumed (sym, loc, name); +} + +static void +resolve_oacc_deviceptr_clause (gfc_symbol *sym, locus loc, const char *name) +{ + if (sym->attr.pointer + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.class_pointer)) + gfc_error ("POINTER object '%s' in %s clause at %L", + sym->name, name, &loc); + if (sym->attr.cray_pointer + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.cray_pointer)) + gfc_error ("Cray pointer object '%s' in %s clause at %L", + sym->name, name, &loc); + if (sym->attr.cray_pointee + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.cray_pointee)) + gfc_error ("Cray pointee object '%s' in %s clause at %L", + sym->name, name, &loc); + if (sym->attr.allocatable + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) + && CLASS_DATA (sym)->attr.allocatable)) + gfc_error ("ALLOCATABLE object '%s' in %s clause at %L", + sym->name, name, &loc); + if (sym->attr.value) + gfc_error ("VALUE object '%s' in %s clause at %L", + sym->name, name, &loc); + check_array_not_assumed (sym, loc, name); +} + + struct resolve_omp_udr_callback_data { gfc_symbol *sym1, *sym2; @@ -2013,19 +2834,45 @@ resolve_omp_udr_clause (gfc_omp_namelist *n, gfc_namespace *ns, return copy; } +/* Returns true if clause in list 'list' is compatible with any of + of the clauses in lists [0..list-1]. E.g., a reduction variable may + appear in both reduction and private clauses, so this function + will return true in this case. */ + +static bool +oacc_compatible_clauses (gfc_omp_clauses *clauses, int list, + gfc_symbol *sym, bool openacc) +{ + gfc_omp_namelist *n; + + if (!openacc) + return false; + + if (list != OMP_LIST_REDUCTION) + return false; + + for (n = clauses->lists[OMP_LIST_FIRST]; n; n = n->next) + if (n->sym == sym) + return true; + + return false; +} /* OpenMP directive resolving routines. */ static void resolve_omp_clauses (gfc_code *code, locus *where, - gfc_omp_clauses *omp_clauses, gfc_namespace *ns) + gfc_omp_clauses *omp_clauses, gfc_namespace *ns, + bool openacc = false) { gfc_omp_namelist *n; + gfc_expr_list *el; int list; static const char *clause_names[] = { "PRIVATE", "FIRSTPRIVATE", "LASTPRIVATE", "COPYPRIVATE", "SHARED", "COPYIN", "UNIFORM", "ALIGNED", "LINEAR", "DEPEND", "MAP", - "TO", "FROM", "REDUCTION" }; + "TO", "FROM", "REDUCTION", "DEVICE_RESIDENT", "USE_DEVICE", + "CACHE" }; if (omp_clauses == NULL) return; @@ -2115,12 +2962,13 @@ resolve_omp_clauses (gfc_code *code, locus *where, && list != OMP_LIST_LASTPRIVATE && list != OMP_LIST_ALIGNED && list != OMP_LIST_DEPEND - && list != OMP_LIST_MAP + && (list != OMP_LIST_MAP || openacc) && list != OMP_LIST_FROM && list != OMP_LIST_TO) for (n = omp_clauses->lists[list]; n; n = n->next) { - if (n->sym->mark) + if (n->sym->mark && !oacc_compatible_clauses (omp_clauses, list, + n->sym, openacc)) gfc_error ("Symbol %qs present on multiple clauses at %L", n->sym->name, where); else @@ -2262,53 +3110,64 @@ resolve_omp_clauses (gfc_code *code, locus *where, case OMP_LIST_TO: case OMP_LIST_FROM: for (; n != NULL; n = n->next) - if (n->expr) - { - if (!gfc_resolve_expr (n->expr) - || n->expr->expr_type != EXPR_VARIABLE - || n->expr->ref == NULL - || n->expr->ref->next - || n->expr->ref->type != REF_ARRAY) - gfc_error ("%qs in %s clause at %L is not a proper " - "array section", n->sym->name, name, where); - else if (n->expr->ref->u.ar.codimen) - gfc_error ("Coarrays not supported in %s clause at %L", - name, where); - else - { - int i; - gfc_array_ref *ar = &n->expr->ref->u.ar; - for (i = 0; i < ar->dimen; i++) - if (ar->stride[i]) - { - gfc_error ("Stride should not be specified for " - "array section in %s clause at %L", - name, where); - break; - } - else if (ar->dimen_type[i] != DIMEN_ELEMENT - && ar->dimen_type[i] != DIMEN_RANGE) - { - gfc_error ("%qs in %s clause at %L is not a " - "proper array section", - n->sym->name, name, where); - break; - } - else if (list == OMP_LIST_DEPEND - && ar->start[i] - && ar->start[i]->expr_type == EXPR_CONSTANT - && ar->end[i] - && ar->end[i]->expr_type == EXPR_CONSTANT - && mpz_cmp (ar->start[i]->value.integer, - ar->end[i]->value.integer) > 0) - { - gfc_error ("%qs in DEPEND clause at %L is a zero " - "size array section", n->sym->name, - where); - break; - } - } - } + { + if (n->expr) + { + if (!gfc_resolve_expr (n->expr) + || n->expr->expr_type != EXPR_VARIABLE + || n->expr->ref == NULL + || n->expr->ref->next + || n->expr->ref->type != REF_ARRAY) + gfc_error ("%qs in %s clause at %L is not a proper " + "array section", n->sym->name, name, where); + else if (n->expr->ref->u.ar.codimen) + gfc_error ("Coarrays not supported in %s clause at %L", + name, where); + else + { + int i; + gfc_array_ref *ar = &n->expr->ref->u.ar; + for (i = 0; i < ar->dimen; i++) + if (ar->stride[i]) + { + gfc_error ("Stride should not be specified for " + "array section in %s clause at %L", + name, where); + break; + } + else if (ar->dimen_type[i] != DIMEN_ELEMENT + && ar->dimen_type[i] != DIMEN_RANGE) + { + gfc_error ("%qs in %s clause at %L is not a " + "proper array section", + n->sym->name, name, where); + break; + } + else if (list == OMP_LIST_DEPEND + && ar->start[i] + && ar->start[i]->expr_type == EXPR_CONSTANT + && ar->end[i] + && ar->end[i]->expr_type == EXPR_CONSTANT + && mpz_cmp (ar->start[i]->value.integer, + ar->end[i]->value.integer) > 0) + { + gfc_error ("%qs in DEPEND clause at %L is a " + "zero size array section", + n->sym->name, where); + break; + } + } + } + else if (openacc) + { + if (list == OMP_LIST_MAP + && n->u.map_op == OMP_MAP_FORCE_DEVICEPTR) + resolve_oacc_deviceptr_clause (n->sym, *where, name); + else + resolve_oacc_data_clauses (n->sym, *where, name); + } + } + if (list != OMP_LIST_DEPEND) for (n = omp_clauses->lists[list]; n != NULL; n = n->next) { @@ -2346,7 +3205,10 @@ resolve_omp_clauses (gfc_code *code, locus *where, gfc_error ("Cray pointer %qs in %s clause at %L", n->sym->name, name, where); } - if (n->sym->as && n->sym->as->type == AS_ASSUMED_SIZE) + if (code + && (oacc_is_loop (code) || code->op == EXEC_OACC_PARALLEL)) + check_array_not_assumed (n->sym, *where, name); + else if (n->sym->as && n->sym->as->type == AS_ASSUMED_SIZE) gfc_error ("Assumed size array %qs in %s clause at %L", n->sym->name, name, where); if (n->sym->attr.in_namelist && list != OMP_LIST_REDUCTION) @@ -2366,6 +3228,7 @@ resolve_omp_clauses (gfc_code *code, locus *where, default: break; } + switch (list) { case OMP_LIST_REDUCTION: @@ -2499,6 +3362,30 @@ resolve_omp_clauses (gfc_code *code, locus *where, to be done here for OMP_LIST_PRIVATE. */ case OMP_LIST_PRIVATE: gcc_assert (code && code->op != EXEC_NOP); + break; + case OMP_LIST_USE_DEVICE: + if (n->sym->attr.allocatable + || (n->sym->ts.type == BT_CLASS && CLASS_DATA (n->sym) + && CLASS_DATA (n->sym)->attr.allocatable)) + gfc_error ("ALLOCATABLE object '%s' in %s clause at %L", + n->sym->name, name, where); + if (n->sym->attr.pointer + || (n->sym->ts.type == BT_CLASS && CLASS_DATA (n->sym) + && CLASS_DATA (n->sym)->attr.class_pointer)) + gfc_error ("POINTER object '%s' in %s clause at %L", + n->sym->name, name, where); + if (n->sym->attr.cray_pointer) + gfc_error ("Cray pointer object '%s' in %s clause at %L", + n->sym->name, name, where); + if (n->sym->attr.cray_pointee) + gfc_error ("Cray pointee object '%s' in %s clause at %L", + n->sym->name, name, where); + /* FALLTHRU */ + case OMP_LIST_DEVICE_RESIDENT: + case OMP_LIST_CACHE: + check_symbol_not_pointer (n->sym, *where, name); + check_array_not_assumed (n->sym, *where, name); + break; default: break; } @@ -2554,6 +3441,25 @@ resolve_omp_clauses (gfc_code *code, locus *where, gfc_error ("THREAD_LIMIT clause at %L requires a scalar " "INTEGER expression", &expr->where); } + if (omp_clauses->async) + if (omp_clauses->async_expr) + resolve_oacc_scalar_int_expr (omp_clauses->async_expr, "ASYNC"); + if (omp_clauses->num_gangs_expr) + resolve_oacc_positive_int_expr (omp_clauses->num_gangs_expr, "NUM_GANGS"); + if (omp_clauses->num_workers_expr) + resolve_oacc_positive_int_expr (omp_clauses->num_workers_expr, "NUM_WORKERS"); + if (omp_clauses->vector_length_expr) + resolve_oacc_positive_int_expr (omp_clauses->vector_length_expr, "VECTOR_LENGTH"); + if (omp_clauses->gang_expr) + resolve_oacc_positive_int_expr (omp_clauses->gang_expr, "GANG"); + if (omp_clauses->worker_expr) + resolve_oacc_positive_int_expr (omp_clauses->worker_expr, "WORKER"); + if (omp_clauses->vector_expr) + resolve_oacc_positive_int_expr (omp_clauses->vector_expr, "VECTOR"); + if (omp_clauses->wait) + if (omp_clauses->wait_list) + for (el = omp_clauses->wait_list; el; el = el->next) + resolve_oacc_scalar_int_expr (el->expr, "WAIT"); } @@ -3021,6 +3927,7 @@ struct fortran_omp_context hash_set<gfc_symbol *> *sharing_clauses; hash_set<gfc_symbol *> *private_iterators; struct fortran_omp_context *previous; + bool is_openmp; } *omp_current_ctx; static gfc_code *omp_current_do_code; static int omp_current_do_collapse; @@ -3065,6 +3972,7 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns) ctx.sharing_clauses = new hash_set<gfc_symbol *>; ctx.private_iterators = new hash_set<gfc_symbol *>; ctx.previous = omp_current_ctx; + ctx.is_openmp = true; omp_current_ctx = &ctx; for (list = 0; list < OMP_LIST_NUM; list++) @@ -3159,7 +4067,12 @@ gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym) if (omp_current_ctx == NULL) return; - if (omp_current_ctx->sharing_clauses->contains (sym)) + /* An openacc context may represent a data clause. Abort if so. */ + if (!omp_current_ctx->is_openmp && !oacc_is_loop (omp_current_ctx->code)) + return; + + if (omp_current_ctx->is_openmp + && omp_current_ctx->sharing_clauses->contains (sym)) return; if (! omp_current_ctx->private_iterators->add (sym)) @@ -3340,6 +4253,428 @@ resolve_omp_do (gfc_code *code) } } +static bool +oacc_is_parallel (gfc_code *code) +{ + return code->op == EXEC_OACC_PARALLEL || code->op == EXEC_OACC_PARALLEL_LOOP; +} + +static bool +oacc_is_kernels (gfc_code *code) +{ + return code->op == EXEC_OACC_KERNELS || code->op == EXEC_OACC_KERNELS_LOOP; +} + +static gfc_statement +omp_code_to_statement (gfc_code *code) +{ + switch (code->op) + { + case EXEC_OMP_PARALLEL: + return ST_OMP_PARALLEL; + case EXEC_OMP_PARALLEL_SECTIONS: + return ST_OMP_PARALLEL_SECTIONS; + case EXEC_OMP_SECTIONS: + return ST_OMP_SECTIONS; + case EXEC_OMP_ORDERED: + return ST_OMP_ORDERED; + case EXEC_OMP_CRITICAL: + return ST_OMP_CRITICAL; + case EXEC_OMP_MASTER: + return ST_OMP_MASTER; + case EXEC_OMP_SINGLE: + return ST_OMP_SINGLE; + case EXEC_OMP_TASK: + return ST_OMP_TASK; + case EXEC_OMP_WORKSHARE: + return ST_OMP_WORKSHARE; + case EXEC_OMP_PARALLEL_WORKSHARE: + return ST_OMP_PARALLEL_WORKSHARE; + case EXEC_OMP_DO: + return ST_OMP_DO; + default: + gcc_unreachable (); + } +} + +static gfc_statement +oacc_code_to_statement (gfc_code *code) +{ + switch (code->op) + { + case EXEC_OACC_PARALLEL: + return ST_OACC_PARALLEL; + case EXEC_OACC_KERNELS: + return ST_OACC_KERNELS; + case EXEC_OACC_DATA: + return ST_OACC_DATA; + case EXEC_OACC_HOST_DATA: + return ST_OACC_HOST_DATA; + case EXEC_OACC_PARALLEL_LOOP: + return ST_OACC_PARALLEL_LOOP; + case EXEC_OACC_KERNELS_LOOP: + return ST_OACC_KERNELS_LOOP; + case EXEC_OACC_LOOP: + return ST_OACC_LOOP; + default: + gcc_unreachable (); + } +} + +static void +resolve_oacc_directive_inside_omp_region (gfc_code *code) +{ + if (omp_current_ctx != NULL && omp_current_ctx->is_openmp) + { + gfc_statement st = omp_code_to_statement (omp_current_ctx->code); + gfc_statement oacc_st = oacc_code_to_statement (code); + gfc_error ("The %s directive cannot be specified within " + "a %s region at %L", gfc_ascii_statement (oacc_st), + gfc_ascii_statement (st), &code->loc); + } +} + +static void +resolve_omp_directive_inside_oacc_region (gfc_code *code) +{ + if (omp_current_ctx != NULL && !omp_current_ctx->is_openmp) + { + gfc_statement st = oacc_code_to_statement (omp_current_ctx->code); + gfc_statement omp_st = omp_code_to_statement (code); + gfc_error ("The %s directive cannot be specified within " + "a %s region at %L", gfc_ascii_statement (omp_st), + gfc_ascii_statement (st), &code->loc); + } +} + + +static void +resolve_oacc_nested_loops (gfc_code *code, gfc_code* do_code, int collapse, + const char *clause) +{ + gfc_symbol *dovar; + gfc_code *c; + int i; + + for (i = 1; i <= collapse; i++) + { + if (do_code->op == EXEC_DO_WHILE) + { + gfc_error ("!$ACC LOOP cannot be a DO WHILE or DO without loop control " + "at %L", &do_code->loc); + break; + } + gcc_assert (do_code->op == EXEC_DO || do_code->op == EXEC_DO_CONCURRENT); + if (do_code->ext.iterator->var->ts.type != BT_INTEGER) + gfc_error ("!$ACC LOOP iteration variable must be of type integer at %L", + &do_code->loc); + dovar = do_code->ext.iterator->var->symtree->n.sym; + if (i > 1) + { + gfc_code *do_code2 = code->block->next; + int j; + + for (j = 1; j < i; j++) + { + gfc_symbol *ivar = do_code2->ext.iterator->var->symtree->n.sym; + if (dovar == ivar + || gfc_find_sym_in_expr (ivar, do_code->ext.iterator->start) + || gfc_find_sym_in_expr (ivar, do_code->ext.iterator->end) + || gfc_find_sym_in_expr (ivar, do_code->ext.iterator->step)) + { + gfc_error ("!$ACC LOOP %s loops don't form rectangular iteration space at %L", + clause, &do_code->loc); + break; + } + if (j < i) + break; + do_code2 = do_code2->block->next; + } + } + if (i == collapse) + break; + for (c = do_code->next; c; c = c->next) + if (c->op != EXEC_NOP && c->op != EXEC_CONTINUE) + { + gfc_error ("%s !$ACC LOOP loops not perfectly nested at %L", + clause, &c->loc); + break; + } + if (c) + break; + do_code = do_code->block; + if (do_code->op != EXEC_DO && do_code->op != EXEC_DO_WHILE + && do_code->op != EXEC_DO_CONCURRENT) + { + gfc_error ("not enough DO loops for %s !$ACC LOOP at %L", + clause, &code->loc); + break; + } + do_code = do_code->next; + if (do_code == NULL + || (do_code->op != EXEC_DO && do_code->op != EXEC_DO_WHILE + && do_code->op != EXEC_DO_CONCURRENT)) + { + gfc_error ("not enough DO loops for %s !$ACC LOOP at %L", + clause, &code->loc); + break; + } + } +} + + +static void +resolve_oacc_params_in_parallel (gfc_code *code, const char *clause) +{ + fortran_omp_context *c; + + if (oacc_is_parallel (code)) + gfc_error ("!$ACC LOOP %s in PARALLEL region doesn't allow " + "non-static arguments at %L", clause, &code->loc); + for (c = omp_current_ctx; c; c = c->previous) + { + if (oacc_is_loop (c->code)) + break; + if (oacc_is_parallel (c->code)) + gfc_error ("!$ACC LOOP %s in PARALLEL region doesn't allow " + "non-static arguments at %L", clause, &code->loc); + } +} + + +static void +resolve_oacc_loop_blocks (gfc_code *code) +{ + fortran_omp_context *c; + + if (!oacc_is_loop (code)) + return; + + if (code->op == EXEC_OACC_LOOP) + for (c = omp_current_ctx; c; c = c->previous) + { + if (oacc_is_loop (c->code)) + { + if (code->ext.omp_clauses->gang) + { + if (c->code->ext.omp_clauses->gang) + gfc_error ("Loop parallelized across gangs is not allowed " + "inside another loop parallelized across gangs at %L", + &code->loc); + if (c->code->ext.omp_clauses->worker) + gfc_error ("Loop parallelized across gangs is not allowed " + "inside loop parallelized across workers at %L", + &code->loc); + if (c->code->ext.omp_clauses->vector) + gfc_error ("Loop parallelized across gangs is not allowed " + "inside loop parallelized across workers at %L", + &code->loc); + } + if (code->ext.omp_clauses->worker) + { + if (c->code->ext.omp_clauses->worker) + gfc_error ("Loop parallelized across workers is not allowed " + "inside another loop parallelized across workers at %L", + &code->loc); + if (c->code->ext.omp_clauses->vector) + gfc_error ("Loop parallelized across workers is not allowed " + "inside another loop parallelized across vectors at %L", + &code->loc); + } + if (code->ext.omp_clauses->vector) + if (c->code->ext.omp_clauses->vector) + gfc_error ("Loop parallelized across vectors is not allowed " + "inside another loop parallelized across vectors at %L", + &code->loc); + } + + if (oacc_is_parallel (c->code) || oacc_is_kernels (c->code)) + break; + } + + if (code->ext.omp_clauses->seq) + { + if (code->ext.omp_clauses->independent) + gfc_error ("Clause SEQ conflicts with INDEPENDENT at %L", &code->loc); + if (code->ext.omp_clauses->gang) + gfc_error ("Clause SEQ conflicts with GANG at %L", &code->loc); + if (code->ext.omp_clauses->worker) + gfc_error ("Clause SEQ conflicts with WORKER at %L", &code->loc); + if (code->ext.omp_clauses->vector) + gfc_error ("Clause SEQ conflicts with VECTOR at %L", &code->loc); + if (code->ext.omp_clauses->par_auto) + gfc_error ("Clause SEQ conflicts with AUTO at %L", &code->loc); + } + if (code->ext.omp_clauses->par_auto) + { + if (code->ext.omp_clauses->gang) + gfc_error ("Clause AUTO conflicts with GANG at %L", &code->loc); + if (code->ext.omp_clauses->worker) + gfc_error ("Clause AUTO conflicts with WORKER at %L", &code->loc); + if (code->ext.omp_clauses->vector) + gfc_error ("Clause AUTO conflicts with VECTOR at %L", &code->loc); + } + if (!code->ext.omp_clauses->tile_list) + { + if (code->ext.omp_clauses->gang) + { + if (code->ext.omp_clauses->worker) + gfc_error ("Clause GANG conflicts with WORKER at %L", &code->loc); + if (code->ext.omp_clauses->vector) + gfc_error ("Clause GANG conflicts with VECTOR at %L", &code->loc); + } + if (code->ext.omp_clauses->worker) + if (code->ext.omp_clauses->vector) + gfc_error ("Clause WORKER conflicts with VECTOR at %L", &code->loc); + } + else if (code->ext.omp_clauses->gang + && code->ext.omp_clauses->worker + && code->ext.omp_clauses->vector) + gfc_error ("Tiled loop cannot be parallelized across gangs, workers and " + "vectors at the same time at %L", &code->loc); + + if (code->ext.omp_clauses->gang + && code->ext.omp_clauses->gang_expr + && !code->ext.omp_clauses->gang_static) + resolve_oacc_params_in_parallel (code, "GANG"); + + if (code->ext.omp_clauses->worker + && code->ext.omp_clauses->worker_expr) + resolve_oacc_params_in_parallel (code, "WORKER"); + + if (code->ext.omp_clauses->tile_list) + { + gfc_expr_list *el; + int num = 0; + for (el = code->ext.omp_clauses->tile_list; el; el = el->next) + { + num++; + if (el->expr == NULL) + continue; + resolve_oacc_positive_int_expr (el->expr, "TILE"); + if (el->expr->expr_type != EXPR_CONSTANT) + gfc_error ("TILE requires constant expression at %L", &code->loc); + } + resolve_oacc_nested_loops (code, code->block->next, num, "tiled"); + } +} + + +void +gfc_resolve_oacc_blocks (gfc_code *code, gfc_namespace *ns) +{ + fortran_omp_context ctx; + + resolve_oacc_loop_blocks (code); + + ctx.code = code; + ctx.sharing_clauses = NULL; + ctx.private_iterators = new hash_set<gfc_symbol *>; + ctx.previous = omp_current_ctx; + ctx.is_openmp = false; + omp_current_ctx = &ctx; + + gfc_resolve_blocks (code->block, ns); + + omp_current_ctx = ctx.previous; + delete ctx.private_iterators; +} + + +static void +resolve_oacc_loop (gfc_code *code) +{ + gfc_code *do_code; + int collapse; + + if (code->ext.omp_clauses) + resolve_omp_clauses (code, &code->loc, code->ext.omp_clauses, NULL, true); + + do_code = code->block->next; + collapse = code->ext.omp_clauses->collapse; + + if (collapse <= 0) + collapse = 1; + resolve_oacc_nested_loops (code, do_code, collapse, "collapsed"); +} + + +static void +resolve_oacc_cache (gfc_code *code ATTRIBUTE_UNUSED) +{ + sorry ("Sorry, !$ACC cache unimplemented yet"); +} + + +void +gfc_resolve_oacc_declare (gfc_namespace *ns) +{ + int list; + gfc_omp_namelist *n; + locus loc; + + if (ns->oacc_declare_clauses == NULL) + return; + + loc = ns->oacc_declare_clauses->loc; + + for (list = OMP_LIST_DEVICE_RESIDENT; + list <= OMP_LIST_DEVICE_RESIDENT; list++) + for (n = ns->oacc_declare_clauses->lists[list]; n; n = n->next) + { + n->sym->mark = 0; + if (n->sym->attr.flavor == FL_PARAMETER) + gfc_error ("PARAMETER object '%s' is not allowed at %L", n->sym->name, &loc); + } + + for (list = OMP_LIST_DEVICE_RESIDENT; + list <= OMP_LIST_DEVICE_RESIDENT; list++) + for (n = ns->oacc_declare_clauses->lists[list]; n; n = n->next) + { + if (n->sym->mark) + gfc_error ("Symbol '%s' present on multiple clauses at %L", + n->sym->name, &loc); + else + n->sym->mark = 1; + } + + for (n = ns->oacc_declare_clauses->lists[OMP_LIST_DEVICE_RESIDENT]; n; + n = n->next) + check_array_not_assumed (n->sym, loc, "DEVICE_RESIDENT"); +} + + +void +gfc_resolve_oacc_directive (gfc_code *code, gfc_namespace *ns ATTRIBUTE_UNUSED) +{ + resolve_oacc_directive_inside_omp_region (code); + + switch (code->op) + { + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_UPDATE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: + case EXEC_OACC_WAIT: + resolve_omp_clauses (code, &code->loc, code->ext.omp_clauses, NULL, + true); + break; + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_LOOP: + resolve_oacc_loop (code); + break; + case EXEC_OACC_CACHE: + resolve_oacc_cache (code); + break; + default: + break; + } +} + /* Resolve OpenMP directive clauses and check various requirements of each directive. */ @@ -3347,6 +4682,8 @@ resolve_omp_do (gfc_code *code) void gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns ATTRIBUTE_UNUSED) { + resolve_omp_directive_inside_oacc_region (code); + if (code->op != EXEC_OMP_ATOMIC) gfc_maybe_initialize_eh (); diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 1c8294e..fd7d4eb 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -585,6 +585,93 @@ decode_statement (void) } while (0); static gfc_statement +decode_oacc_directive (void) +{ + locus old_locus; + char c; + + gfc_enforce_clean_symbol_state (); + + gfc_clear_error (); /* Clear any pending errors. */ + gfc_clear_warning (); /* Clear any pending warnings. */ + + if (gfc_pure (NULL)) + { + gfc_error_now ("OpenACC directives at %C may not appear in PURE " + "procedures"); + gfc_error_recovery (); + return ST_NONE; + } + + gfc_unset_implicit_pure (NULL); + + old_locus = gfc_current_locus; + + /* General OpenACC directive matching: Instead of testing every possible + statement, we eliminate most possibilities by peeking at the + first character. */ + + c = gfc_peek_ascii_char (); + + switch (c) + { + case 'c': + match ("cache", gfc_match_oacc_cache, ST_OACC_CACHE); + break; + case 'd': + match ("data", gfc_match_oacc_data, ST_OACC_DATA); + match ("declare", gfc_match_oacc_declare, ST_OACC_DECLARE); + break; + case 'e': + match ("end data", gfc_match_omp_eos, ST_OACC_END_DATA); + match ("end host_data", gfc_match_omp_eos, ST_OACC_END_HOST_DATA); + match ("end kernels loop", gfc_match_omp_eos, ST_OACC_END_KERNELS_LOOP); + match ("end kernels", gfc_match_omp_eos, ST_OACC_END_KERNELS); + match ("end loop", gfc_match_omp_eos, ST_OACC_END_LOOP); + match ("end parallel loop", gfc_match_omp_eos, ST_OACC_END_PARALLEL_LOOP); + match ("end parallel", gfc_match_omp_eos, ST_OACC_END_PARALLEL); + match ("enter data", gfc_match_oacc_enter_data, ST_OACC_ENTER_DATA); + match ("exit data", gfc_match_oacc_exit_data, ST_OACC_EXIT_DATA); + break; + case 'h': + match ("host_data", gfc_match_oacc_host_data, ST_OACC_HOST_DATA); + break; + case 'p': + match ("parallel loop", gfc_match_oacc_parallel_loop, ST_OACC_PARALLEL_LOOP); + match ("parallel", gfc_match_oacc_parallel, ST_OACC_PARALLEL); + break; + case 'k': + match ("kernels loop", gfc_match_oacc_kernels_loop, ST_OACC_KERNELS_LOOP); + match ("kernels", gfc_match_oacc_kernels, ST_OACC_KERNELS); + break; + case 'l': + match ("loop", gfc_match_oacc_loop, ST_OACC_LOOP); + break; + case 'r': + match ("routine", gfc_match_oacc_routine, ST_OACC_ROUTINE); + break; + case 'u': + match ("update", gfc_match_oacc_update, ST_OACC_UPDATE); + break; + case 'w': + match ("wait", gfc_match_oacc_wait, ST_OACC_WAIT); + break; + } + + /* Directive not found or stored an error message. + Check and give up. */ + + if (gfc_error_check () == 0) + gfc_error_now ("Unclassifiable OpenACC directive at %C"); + + reject_statement (); + + gfc_error_recovery (); + + return ST_NONE; +} + +static gfc_statement decode_omp_directive (void) { locus old_locus; @@ -811,6 +898,23 @@ decode_gcc_attribute (void) #undef match +/* Assert next length characters to be equal to token in free form. */ + +static void +verify_token_free (const char* token, int length, bool last_was_use_stmt) +{ + int i; + char c; + + c = gfc_next_ascii_char (); + for (i = 0; i < length; i++, c = gfc_next_ascii_char ()) + gcc_assert (c == token[i]); + + gcc_assert (gfc_is_whitespace(c)); + gfc_gobble_whitespace (); + if (last_was_use_stmt) + use_modules (); +} /* Get the next statement in free form source. */ @@ -880,7 +984,7 @@ next_free (void) else if (c == '!') { /* Comments have already been skipped by the time we get here, - except for GCC attributes and OpenMP directives. */ + except for GCC attributes and OpenMP/OpenACC directives. */ gfc_next_ascii_char (); /* Eat up the exclamation sign. */ c = gfc_peek_ascii_char (); @@ -897,21 +1001,39 @@ next_free (void) return decode_gcc_attribute (); } - else if (c == '$' && (flag_openmp || flag_openmp_simd)) + else if (c == '$') { - int i; - - c = gfc_next_ascii_char (); - for (i = 0; i < 4; i++, c = gfc_next_ascii_char ()) - gcc_assert (c == "$omp"[i]); + /* Since both OpenMP and OpenACC directives starts with + !$ character sequence, we must check all flags combinations */ + if ((flag_openmp || flag_openmp_simd) + && !flag_openacc) + { + verify_token_free ("$omp", 4, last_was_use_stmt); + return decode_omp_directive (); + } + else if ((flag_openmp || flag_openmp_simd) + && flag_openacc) + { + gfc_next_ascii_char (); /* Eat up dollar character */ + c = gfc_peek_ascii_char (); - gcc_assert (c == ' ' || c == '\t'); - gfc_gobble_whitespace (); - if (last_was_use_stmt) - use_modules (); - return decode_omp_directive (); + if (c == 'o') + { + verify_token_free ("omp", 3, last_was_use_stmt); + return decode_omp_directive (); + } + else if (c == 'a') + { + verify_token_free ("acc", 3, last_was_use_stmt); + return decode_oacc_directive (); + } + } + else if (flag_openacc) + { + verify_token_free ("$acc", 4, last_was_use_stmt); + return decode_oacc_directive (); + } } - gcc_unreachable (); } @@ -927,6 +1049,28 @@ next_free (void) return decode_statement (); } +/* Assert next length characters to be equal to token in fixed form. */ + +static bool +verify_token_fixed (const char *token, int length, bool last_was_use_stmt) +{ + int i; + char c = gfc_next_char_literal (NONSTRING); + + for (i = 0; i < length; i++, c = gfc_next_char_literal (NONSTRING)) + gcc_assert ((char) gfc_wide_tolower (c) == token[i]); + + if (c != ' ' && c != '0') + { + gfc_buffer_error (false); + gfc_error ("Bad continuation line at %C"); + return false; + } + if (last_was_use_stmt) + use_modules (); + + return true; +} /* Get the next statement in fixed-form source. */ @@ -986,21 +1130,38 @@ next_fixed (void) return decode_gcc_attribute (); } - else if (c == '$' - && (flag_openmp || flag_openmp_simd)) + else if (c == '$') { - for (i = 0; i < 4; i++, c = gfc_next_char_literal (NONSTRING)) - gcc_assert ((char) gfc_wide_tolower (c) == "$omp"[i]); - - if (c != ' ' && c != '0') + if ((flag_openmp || flag_openmp_simd) + && !flag_openacc) { - gfc_buffer_error (false); - gfc_error ("Bad continuation line at %C"); - return ST_NONE; + if (!verify_token_fixed ("omp", 3, last_was_use_stmt)) + return ST_NONE; + return decode_omp_directive (); + } + else if ((flag_openmp || flag_openmp_simd) + && flag_openacc) + { + c = gfc_next_char_literal(NONSTRING); + if (c == 'o' || c == 'O') + { + if (!verify_token_fixed ("mp", 2, last_was_use_stmt)) + return ST_NONE; + return decode_omp_directive (); + } + else if (c == 'a' || c == 'A') + { + if (!verify_token_fixed ("cc", 2, last_was_use_stmt)) + return ST_NONE; + return decode_oacc_directive (); + } + } + else if (flag_openacc) + { + if (!verify_token_fixed ("acc", 3, last_was_use_stmt)) + return ST_NONE; + return decode_oacc_directive (); } - if (last_was_use_stmt) - use_modules (); - return decode_omp_directive (); } /* FALLTHROUGH */ @@ -1161,7 +1322,9 @@ next_statement (void) case ST_OMP_BARRIER: case ST_OMP_TASKWAIT: case ST_OMP_TASKYIELD: \ case ST_OMP_CANCEL: case ST_OMP_CANCELLATION_POINT: \ case ST_OMP_TARGET_UPDATE: case ST_ERROR_STOP: case ST_SYNC_ALL: \ - case ST_SYNC_IMAGES: case ST_SYNC_MEMORY: case ST_LOCK: case ST_UNLOCK + case ST_SYNC_IMAGES: case ST_SYNC_MEMORY: case ST_LOCK: case ST_UNLOCK: \ + case ST_OACC_UPDATE: case ST_OACC_WAIT: case ST_OACC_CACHE: \ + case ST_OACC_ENTER_DATA: case ST_OACC_EXIT_DATA /* Statements that mark other executable statements. */ @@ -1186,7 +1349,9 @@ next_statement (void) case ST_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD: case ST_OMP_DISTRIBUTE: \ case ST_OMP_DISTRIBUTE_SIMD: case ST_OMP_DISTRIBUTE_PARALLEL_DO: \ case ST_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: \ - case ST_CRITICAL + case ST_CRITICAL: \ + case ST_OACC_PARALLEL_LOOP: case ST_OACC_PARALLEL: case ST_OACC_KERNELS: \ + case ST_OACC_DATA: case ST_OACC_HOST_DATA: case ST_OACC_LOOP: case ST_OACC_KERNELS_LOOP /* Declaration statements */ @@ -1194,7 +1359,7 @@ next_statement (void) case ST_EQUIVALENCE: case ST_NAMELIST: case ST_STATEMENT_FUNCTION: \ case ST_TYPE: case ST_INTERFACE: case ST_OMP_THREADPRIVATE: \ case ST_PROCEDURE: case ST_OMP_DECLARE_SIMD: case ST_OMP_DECLARE_REDUCTION: \ - case ST_OMP_DECLARE_TARGET + case ST_OMP_DECLARE_TARGET: case ST_OACC_ROUTINE /* Block end statements. Errors associated with interchanging these are detected in gfc_match_end(). */ @@ -1214,6 +1379,8 @@ push_state (gfc_state_data *p, gfc_compile_state new_state, gfc_symbol *sym) p->sym = sym; p->head = p->tail = NULL; p->do_variable = NULL; + if (p->state != COMP_DO && p->state != COMP_DO_CONCURRENT) + p->ext.oacc_declare_clauses = NULL; /* If this the state of a construct like BLOCK, DO or IF, the corresponding construct statement was accepted right before pushing the state. Thus, @@ -1679,6 +1846,69 @@ gfc_ascii_statement (gfc_statement st) case ST_END_ENUM: p = "END ENUM"; break; + case ST_OACC_PARALLEL_LOOP: + p = "!$ACC PARALLEL LOOP"; + break; + case ST_OACC_END_PARALLEL_LOOP: + p = "!$ACC END PARALLEL LOOP"; + break; + case ST_OACC_PARALLEL: + p = "!$ACC PARALLEL"; + break; + case ST_OACC_END_PARALLEL: + p = "!$ACC END PARALLEL"; + break; + case ST_OACC_KERNELS: + p = "!$ACC KERNELS"; + break; + case ST_OACC_END_KERNELS: + p = "!$ACC END KERNELS"; + break; + case ST_OACC_KERNELS_LOOP: + p = "!$ACC KERNELS LOOP"; + break; + case ST_OACC_END_KERNELS_LOOP: + p = "!$ACC END KERNELS LOOP"; + break; + case ST_OACC_DATA: + p = "!$ACC DATA"; + break; + case ST_OACC_END_DATA: + p = "!$ACC END DATA"; + break; + case ST_OACC_HOST_DATA: + p = "!$ACC HOST_DATA"; + break; + case ST_OACC_END_HOST_DATA: + p = "!$ACC END HOST_DATA"; + break; + case ST_OACC_LOOP: + p = "!$ACC LOOP"; + break; + case ST_OACC_END_LOOP: + p = "!$ACC END LOOP"; + break; + case ST_OACC_DECLARE: + p = "!$ACC DECLARE"; + break; + case ST_OACC_UPDATE: + p = "!$ACC UPDATE"; + break; + case ST_OACC_WAIT: + p = "!$ACC WAIT"; + break; + case ST_OACC_CACHE: + p = "!$ACC CACHE"; + break; + case ST_OACC_ENTER_DATA: + p = "!$ACC ENTER DATA"; + break; + case ST_OACC_EXIT_DATA: + p = "!$ACC EXIT DATA"; + break; + case ST_OACC_ROUTINE: + p = "!$ACC ROUTINE"; + break; case ST_OMP_ATOMIC: p = "!$OMP ATOMIC"; break; @@ -2180,6 +2410,7 @@ verify_st_order (st_state *p, gfc_statement st, bool silent) case ST_PUBLIC: case ST_PRIVATE: case ST_DERIVED_DECL: + case ST_OACC_DECLARE: case_decl: if (p->state >= ORDER_EXEC) goto order; @@ -3081,6 +3312,19 @@ declSt: st = next_statement (); goto loop; + case ST_OACC_DECLARE: + if (!verify_st_order(&ss, st, false)) + { + reject_statement (); + st = next_statement (); + goto loop; + } + if (gfc_state_stack->ext.oacc_declare_clauses == NULL) + gfc_state_stack->ext.oacc_declare_clauses = new_st.ext.omp_clauses; + accept_statement (st); + st = next_statement (); + goto loop; + default: break; } @@ -3571,9 +3815,15 @@ static void parse_critical_block (void) { gfc_code *top, *d; - gfc_state_data s; + gfc_state_data s, *sd; gfc_statement st; + for (sd = gfc_state_stack; sd; sd = sd->previous) + if (sd->state == COMP_OMP_STRUCTURED_BLOCK) + gfc_error_now (is_oacc (sd) + ? "CRITICAL block inside of OpenACC region at %C" + : "CRITICAL block inside of OpenMP region at %C"); + s.ext.end_do_label = new_st.label1; accept_statement (ST_CRITICAL); @@ -3988,6 +4238,128 @@ parse_omp_atomic (void) } +/* Parse the statements of an OpenACC structured block. */ + +static void +parse_oacc_structured_block (gfc_statement acc_st) +{ + gfc_statement st, acc_end_st; + gfc_code *cp, *np; + gfc_state_data s, *sd; + + for (sd = gfc_state_stack; sd; sd = sd->previous) + if (sd->state == COMP_CRITICAL) + gfc_error_now ("OpenACC directive inside of CRITICAL block at %C"); + + accept_statement (acc_st); + + cp = gfc_state_stack->tail; + push_state (&s, COMP_OMP_STRUCTURED_BLOCK, NULL); + np = new_level (cp); + np->op = cp->op; + np->block = NULL; + switch (acc_st) + { + case ST_OACC_PARALLEL: + acc_end_st = ST_OACC_END_PARALLEL; + break; + case ST_OACC_KERNELS: + acc_end_st = ST_OACC_END_KERNELS; + break; + case ST_OACC_DATA: + acc_end_st = ST_OACC_END_DATA; + break; + case ST_OACC_HOST_DATA: + acc_end_st = ST_OACC_END_HOST_DATA; + break; + default: + gcc_unreachable (); + } + + do + { + st = parse_executable (ST_NONE); + if (st == ST_NONE) + unexpected_eof (); + else if (st != acc_end_st) + gfc_error ("Expecting %s at %C", gfc_ascii_statement (acc_end_st)); + reject_statement (); + } + while (st != acc_end_st); + + gcc_assert (new_st.op == EXEC_NOP); + + gfc_clear_new_st (); + gfc_commit_symbols (); + gfc_warning_check (); + pop_state (); +} + +/* Parse the statements of OpenACC loop/parallel loop/kernels loop. */ + +static gfc_statement +parse_oacc_loop (gfc_statement acc_st) +{ + gfc_statement st; + gfc_code *cp, *np; + gfc_state_data s, *sd; + + for (sd = gfc_state_stack; sd; sd = sd->previous) + if (sd->state == COMP_CRITICAL) + gfc_error_now ("OpenACC directive inside of CRITICAL block at %C"); + + accept_statement (acc_st); + + cp = gfc_state_stack->tail; + push_state (&s, COMP_OMP_STRUCTURED_BLOCK, NULL); + np = new_level (cp); + np->op = cp->op; + np->block = NULL; + + for (;;) + { + st = next_statement (); + if (st == ST_NONE) + unexpected_eof (); + else if (st == ST_DO) + break; + else + { + gfc_error ("Expected DO loop at %C"); + reject_statement (); + } + } + + parse_do_block (); + if (gfc_statement_label != NULL + && gfc_state_stack->previous != NULL + && gfc_state_stack->previous->state == COMP_DO + && gfc_state_stack->previous->ext.end_do_label == gfc_statement_label) + { + pop_state (); + return ST_IMPLIED_ENDDO; + } + + check_do_closure (); + pop_state (); + + st = next_statement (); + if (st == ST_OACC_END_LOOP) + gfc_warning ("Redundant !$ACC END LOOP at %C"); + if ((acc_st == ST_OACC_PARALLEL_LOOP && st == ST_OACC_END_PARALLEL_LOOP) || + (acc_st == ST_OACC_KERNELS_LOOP && st == ST_OACC_END_KERNELS_LOOP) || + (acc_st == ST_OACC_LOOP && st == ST_OACC_END_LOOP)) + { + gcc_assert (new_st.op == EXEC_NOP); + gfc_clear_new_st (); + gfc_commit_symbols (); + gfc_warning_check (); + st = next_statement (); + } + return st; +} + + /* Parse the statements of an OpenMP structured block. */ static void @@ -4307,6 +4679,21 @@ parse_executable (gfc_statement st) parse_forall_block (); break; + case ST_OACC_PARALLEL_LOOP: + case ST_OACC_KERNELS_LOOP: + case ST_OACC_LOOP: + st = parse_oacc_loop (st); + if (st == ST_IMPLIED_ENDDO) + return st; + continue; + + case ST_OACC_PARALLEL: + case ST_OACC_KERNELS: + case ST_OACC_DATA: + case ST_OACC_HOST_DATA: + parse_oacc_structured_block (st); + break; + case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: @@ -4637,6 +5024,13 @@ contains: done: gfc_current_ns->code = gfc_state_stack->head; + if (gfc_state_stack->state == COMP_PROGRAM + || gfc_state_stack->state == COMP_MODULE + || gfc_state_stack->state == COMP_SUBROUTINE + || gfc_state_stack->state == COMP_FUNCTION + || gfc_state_stack->state == COMP_BLOCK) + gfc_current_ns->oacc_declare_clauses + = gfc_state_stack->ext.oacc_declare_clauses; } @@ -5155,3 +5549,28 @@ duplicate_main: gfc_done_2 (); return true; } + +/* Return true if this state data represents an OpenACC region. */ +bool +is_oacc (gfc_state_data *sd) +{ + switch (sd->construct->op) + { + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: + return true; + + default: + return false; + } +} diff --git a/gcc/fortran/parse.h b/gcc/fortran/parse.h index d6b45fb..8a1613f 100644 --- a/gcc/fortran/parse.h +++ b/gcc/fortran/parse.h @@ -49,6 +49,7 @@ typedef struct gfc_state_data union { gfc_st_label *end_do_label; + gfc_omp_clauses *oacc_declare_clauses; } ext; } @@ -68,4 +69,5 @@ match gfc_match_enumerator_def (void); void gfc_free_enum_history (void); extern bool gfc_matching_function; match gfc_match_prefix (gfc_typespec *); +bool is_oacc (gfc_state_data *); #endif /* GFC_PARSE_H */ diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 52734e0..88f35ff 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -9126,6 +9126,18 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_WAIT: break; + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: case EXEC_OMP_ATOMIC: case EXEC_OMP_CRITICAL: case EXEC_OMP_DISTRIBUTE: @@ -9941,6 +9953,15 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns) omp_workshare_save = -1; switch (code->op) { + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + gfc_resolve_oacc_blocks (code, ns); + break; case EXEC_OMP_PARALLEL_WORKSHARE: omp_workshare_save = omp_workshare_flag; omp_workshare_flag = 1; @@ -10293,6 +10314,21 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns) "expression", &code->expr1->where); break; + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: + gfc_resolve_oacc_directive (code, ns); + break; + case EXEC_OMP_ATOMIC: case EXEC_OMP_BARRIER: case EXEC_OMP_CANCEL: @@ -14931,6 +14967,7 @@ resolve_codes (gfc_namespace *ns) old_obstack = labels_obstack; bitmap_obstack_initialize (&labels_obstack); + gfc_resolve_oacc_declare (ns); gfc_resolve_code (ns->code, ns); bitmap_obstack_release (&labels_obstack); diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c index f804060..4a71cb2 100644 --- a/gcc/fortran/scanner.c +++ b/gcc/fortran/scanner.c @@ -55,9 +55,12 @@ gfc_directorylist *include_dirs, *intrinsic_modules_dirs; static gfc_file *file_head, *current_file; -static int continue_flag, end_flag, openmp_flag, gcc_attribute_flag; +static int continue_flag, end_flag, gcc_attribute_flag; +/* If !$omp/!$acc occurred in current comment line. */ +static int openmp_flag, openacc_flag; static int continue_count, continue_line; static locus openmp_locus; +static locus openacc_locus; static locus gcc_attribute_locus; gfc_source_form gfc_current_form; @@ -707,11 +710,89 @@ skip_gcc_attribute (locus start) return r; } +/* Return true if CC was matched. */ +static bool +skip_oacc_attribute (locus start, locus old_loc, bool continue_flag) +{ + bool r = false; + char c; + + if ((c = next_char ()) == 'c' || c == 'C') + if ((c = next_char ()) == 'c' || c == 'C') + r = true; + + if (r) + { + if ((c = next_char ()) == ' ' || c == '\t' + || continue_flag) + { + while (gfc_is_whitespace (c)) + c = next_char (); + if (c != '\n' && c != '!') + { + openacc_flag = 1; + openacc_locus = old_loc; + gfc_current_locus = start; + } + else + r = false; + } + else + { + gfc_warning_now ("!$ACC at %C starts a commented " + "line as it neither is followed " + "by a space nor is a " + "continuation line"); + r = false; + } + } + + return r; +} + +/* Return true if MP was matched. */ +static bool +skip_omp_attribute (locus start, locus old_loc, bool continue_flag) +{ + bool r = false; + char c; + + if ((c = next_char ()) == 'm' || c == 'M') + if ((c = next_char ()) == 'p' || c == 'P') + r = true; + + if (r) + { + if ((c = next_char ()) == ' ' || c == '\t' + || continue_flag) + { + while (gfc_is_whitespace (c)) + c = next_char (); + if (c != '\n' && c != '!') + { + openmp_flag = 1; + openmp_locus = old_loc; + gfc_current_locus = start; + } + else + r = false; + } + else + { + gfc_warning_now ("!$OMP at %C starts a commented " + "line as it neither is followed " + "by a space nor is a " + "continuation line"); + r = false; + } + } + return r; +} /* Comment lines are null lines, lines containing only blanks or lines on which the first nonblank line is a '!'. - Return true if !$ openmp conditional compilation sentinel was + Return true if !$ openmp or openacc conditional compilation sentinel was seen. */ static bool @@ -744,55 +825,98 @@ skip_free_comments (void) if (at_bol && skip_gcc_attribute (start)) return false; - /* If -fopenmp, we need to handle here 2 things: - 1) don't treat !$omp as comments, but directives - 2) handle OpenMP conditional compilation, where + /* If -fopenmp/-fopenacc, we need to handle here 2 things: + 1) don't treat !$omp/!$acc as comments, but directives + 2) handle OpenMP/OpenACC conditional compilation, where !$ should be treated as 2 spaces (for initial lines only if followed by space). */ - if ((flag_openmp || flag_openmp_simd) && at_bol) - { - locus old_loc = gfc_current_locus; - if (next_char () == '$') - { - c = next_char (); - if (c == 'o' || c == 'O') - { - if (((c = next_char ()) == 'm' || c == 'M') - && ((c = next_char ()) == 'p' || c == 'P')) + if (at_bol) + { + if ((flag_openmp || flag_openmp_simd) + && flag_openacc) + { + locus old_loc = gfc_current_locus; + if (next_char () == '$') + { + c = next_char (); + if (c == 'o' || c == 'O') + { + if (skip_omp_attribute (start, old_loc, continue_flag)) + return false; + gfc_current_locus = old_loc; + next_char (); + c = next_char (); + } + else if (c == 'a' || c == 'A') + { + if (skip_oacc_attribute (start, old_loc, continue_flag)) + return false; + gfc_current_locus = old_loc; + next_char (); + c = next_char (); + } + if (continue_flag || c == ' ' || c == '\t') + { + gfc_current_locus = old_loc; + next_char (); + openmp_flag = openacc_flag = 0; + return true; + } + } + gfc_current_locus = old_loc; + } + else if ((flag_openmp || flag_openmp_simd) + && !flag_openacc) + { + locus old_loc = gfc_current_locus; + if (next_char () == '$') + { + c = next_char (); + if (c == 'o' || c == 'O') + { + if (skip_omp_attribute (start, old_loc, continue_flag)) + return false; + gfc_current_locus = old_loc; + next_char (); + c = next_char (); + } + if (continue_flag || c == ' ' || c == '\t') + { + gfc_current_locus = old_loc; + next_char (); + openmp_flag = 0; + return true; + } + } + gfc_current_locus = old_loc; + } + else if (flag_openacc + && !(flag_openmp || flag_openmp_simd)) + { + locus old_loc = gfc_current_locus; + if (next_char () == '$') + { + c = next_char (); + if (c == 'a' || c == 'A') { - if ((c = next_char ()) == ' ' || c == '\t' - || continue_flag) - { - while (gfc_is_whitespace (c)) - c = next_char (); - if (c != '\n' && c != '!') - { - openmp_flag = 1; - openmp_locus = old_loc; - gfc_current_locus = start; - return false; - } - } - else - gfc_warning_now ("!$OMP at %C starts a commented " - "line as it neither is followed " - "by a space nor is a " - "continuation line"); + if (skip_oacc_attribute (start, old_loc, + continue_flag)) + return false; + gfc_current_locus = old_loc; + next_char(); + c = next_char(); } - gfc_current_locus = old_loc; - next_char (); - c = next_char (); - } - if (continue_flag || c == ' ' || c == '\t') - { - gfc_current_locus = old_loc; - next_char (); - openmp_flag = 0; - return true; - } - } - gfc_current_locus = old_loc; - } + if (continue_flag || c == ' ' || c == '\t') + { + gfc_current_locus = old_loc; + next_char(); + openacc_flag = 0; + return true; + } + } + gfc_current_locus = old_loc; + } + } skip_comment_line (); continue; } @@ -803,6 +927,9 @@ skip_free_comments (void) if (openmp_flag && at_bol) openmp_flag = 0; + if (openacc_flag && at_bol) + openacc_flag = 0; + gcc_attribute_flag = 0; gfc_current_locus = start; return false; @@ -865,9 +992,10 @@ skip_fixed_comments (void) return; } - /* If -fopenmp, we need to handle here 2 things: - 1) don't treat !$omp|c$omp|*$omp as comments, but directives - 2) handle OpenMP conditional compilation, where + /* If -fopenmp/-fopenacc, we need to handle here 2 things: + 1) don't treat !$omp/!$acc|c$omp/c$acc|*$omp / *$acc as comments, + but directives + 2) handle OpenMP/OpenACC conditional compilation, where !$|c$|*$ should be treated as 2 spaces if the characters in columns 3 to 6 are valid fixed form label columns characters. */ @@ -934,6 +1062,67 @@ skip_fixed_comments (void) } gfc_current_locus = start; } + + if (flag_openacc) + { + if (next_char () == '$') + { + c = next_char (); + if (c == 'a' || c == 'A') + { + if (((c = next_char ()) == 'c' || c == 'C') + && ((c = next_char ()) == 'c' || c == 'C')) + { + c = next_char (); + if (c != '\n' + && ((openacc_flag && continue_flag) + || c == ' ' || c == '\t' || c == '0')) + { + do + c = next_char (); + while (gfc_is_whitespace (c)); + if (c != '\n' && c != '!') + { + /* Canonicalize to *$acc. */ + *start.nextc = '*'; + openacc_flag = 1; + gfc_current_locus = start; + return; + } + } + } + } + else + { + int digit_seen = 0; + + for (col = 3; col < 6; col++, c = next_char ()) + if (c == ' ') + continue; + else if (c == '\t') + { + col = 6; + break; + } + else if (c < '0' || c > '9') + break; + else + digit_seen = 1; + + if (col == 6 && c != '\n' + && ((continue_flag && !digit_seen) + || c == ' ' || c == '\t' || c == '0')) + { + gfc_current_locus = start; + start.nextc[0] = ' '; + start.nextc[1] = ' '; + continue; + } + } + } + gfc_current_locus = start; + } + skip_comment_line (); continue; } @@ -976,6 +1165,7 @@ skip_fixed_comments (void) } openmp_flag = 0; + openacc_flag = 0; gcc_attribute_flag = 0; gfc_current_locus = start; } @@ -1004,10 +1194,11 @@ gfc_char_t gfc_next_char_literal (gfc_instring in_string) { locus old_loc; - int i, prev_openmp_flag; + int i, prev_openmp_flag, prev_openacc_flag; gfc_char_t c; continue_flag = 0; + prev_openacc_flag = prev_openmp_flag = 0; restart: c = next_char (); @@ -1033,6 +1224,11 @@ restart: sizeof (gfc_current_locus)) == 0) goto done; + if (openacc_flag + && memcmp (&gfc_current_locus, &openacc_locus, + sizeof (gfc_current_locus)) == 0) + goto done; + /* This line can't be continued */ do { @@ -1088,7 +1284,11 @@ restart: goto done; } - prev_openmp_flag = openmp_flag; + if (flag_openmp) + prev_openmp_flag = openmp_flag; + if (flag_openacc) + prev_openacc_flag = openacc_flag; + continue_flag = 1; if (c == '!') skip_comment_line (); @@ -1118,13 +1318,23 @@ restart: && continue_line < gfc_linebuf_linenum (gfc_current_locus.lb)) continue_line = gfc_linebuf_linenum (gfc_current_locus.lb); - if (prev_openmp_flag != openmp_flag) - { - gfc_current_locus = old_loc; - openmp_flag = prev_openmp_flag; - c = '&'; - goto done; - } + if (flag_openmp) + if (prev_openmp_flag != openmp_flag) + { + gfc_current_locus = old_loc; + openmp_flag = prev_openmp_flag; + c = '&'; + goto done; + } + + if (flag_openacc) + if (prev_openacc_flag != openacc_flag) + { + gfc_current_locus = old_loc; + openacc_flag = prev_openacc_flag; + c = '&'; + goto done; + } /* Now that we have a non-comment line, probe ahead for the first non-whitespace character. If it is another '&', then @@ -1148,6 +1358,17 @@ restart: while (gfc_is_whitespace (c)) c = next_char (); } + if (openacc_flag) + { + for (i = 0; i < 5; i++, c = next_char ()) + { + gcc_assert (gfc_wide_tolower (c) == (unsigned char) "!$acc"[i]); + if (i == 4) + old_loc = gfc_current_locus; + } + while (gfc_is_whitespace (c)) + c = next_char (); + } if (c != '&') { @@ -1161,7 +1382,7 @@ restart: } /* Both !$omp and !$ -fopenmp continuation lines have & on the continuation line only optionally. */ - else if (openmp_flag || openmp_cond_flag) + else if (openmp_flag || openacc_flag || openmp_cond_flag) gfc_current_locus.nextc--; else { @@ -1199,7 +1420,11 @@ restart: "Line truncated at %L", &gfc_current_locus); } - prev_openmp_flag = openmp_flag; + if (flag_openmp) + prev_openmp_flag = openmp_flag; + if (flag_openacc) + prev_openacc_flag = openacc_flag; + continue_flag = 1; old_loc = gfc_current_locus; @@ -1207,26 +1432,38 @@ restart: skip_fixed_comments (); /* See if this line is a continuation line. */ - if (openmp_flag != prev_openmp_flag) + if (flag_openmp && openmp_flag != prev_openmp_flag) { openmp_flag = prev_openmp_flag; goto not_continuation; } + if (flag_openacc && openacc_flag != prev_openacc_flag) + { + openacc_flag = prev_openacc_flag; + goto not_continuation; + } - if (!openmp_flag) + if (!openmp_flag && !openacc_flag) for (i = 0; i < 5; i++) { c = next_char (); if (c != ' ') goto not_continuation; } - else + else if (openmp_flag) for (i = 0; i < 5; i++) { c = next_char (); if (gfc_wide_tolower (c) != (unsigned char) "*$omp"[i]) goto not_continuation; } + else if (openacc_flag) + for (i = 0; i < 5; i++) + { + c = next_char (); + if (gfc_wide_tolower (c) != (unsigned char) "*$acc"[i]) + goto not_continuation; + } c = next_char (); if (c == '0' || c == ' ' || c == '\n') diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c index 7347e36..116af15 100644 --- a/gcc/fortran/st.c +++ b/gcc/fortran/st.c @@ -185,6 +185,18 @@ gfc_free_statement (gfc_code *p) gfc_free_forall_iterator (p->ext.forall_iterator); break; + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_LOOP: + case EXEC_OACC_UPDATE: + case EXEC_OACC_WAIT: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: case EXEC_OMP_CANCEL: case EXEC_OMP_CANCELLATION_POINT: case EXEC_OMP_DISTRIBUTE: diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 667ebad..cad9b5b 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -5804,6 +5804,13 @@ gfc_generate_function_code (gfc_namespace * ns) if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS) && !sym->attr.is_bind_c) add_argument_checking (&body, sym); + /* Generate !$ACC DECLARE directive. */ + if (ns->oacc_declare_clauses) + { + tree tmp = gfc_trans_oacc_declare (&body, ns); + gfc_add_expr_to_block (&body, tmp); + } + tmp = gfc_trans_code (ns->code); gfc_add_expr_to_block (&body, tmp); diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index e77c191..fe47a96 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "trans-const.h" #include "arith.h" #include "omp-low.h" +#include "gomp-constants.h" int ompws_flags; @@ -1045,7 +1046,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p) return; tree orig_decl = decl; c4 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (c4) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c4, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (c4) = decl; OMP_CLAUSE_SIZE (c4) = size_int (0); decl = build_fold_indirect_ref (decl); @@ -1056,7 +1057,7 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p) || GFC_DECL_GET_SCALAR_ALLOCATABLE (orig_decl))) { c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (c3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (c3) = unshare_expr (decl); OMP_CLAUSE_SIZE (c3) = size_int (0); decl = build_fold_indirect_ref (decl); @@ -1073,11 +1074,11 @@ gfc_omp_finish_clause (tree c, gimple_seq *pre_p) ptr = build_fold_indirect_ref (ptr); OMP_CLAUSE_DECL (c) = ptr; c2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_TO_PSET; + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_TO_PSET); OMP_CLAUSE_DECL (c2) = decl; OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (type); c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (c3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (c3) = gfc_conv_descriptor_data_get (decl); OMP_CLAUSE_SIZE (c3) = size_int (0); tree size = create_tmp_var (gfc_array_index_type); @@ -1718,6 +1719,21 @@ gfc_trans_omp_reduction_list (gfc_omp_namelist *namelist, tree list, return list; } +static inline tree +gfc_convert_expr_to_tree (stmtblock_t *block, gfc_expr *expr) +{ + gfc_se se; + tree result; + + gfc_init_se (&se, NULL ); + gfc_conv_expr (&se, expr); + gfc_add_block_to_block (block, &se.pre); + result = gfc_evaluate_now (se.expr, block); + gfc_add_block_to_block (block, &se.post); + + return result; +} + static tree gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, locus where, bool declare_simd = false) @@ -1761,7 +1777,17 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, goto add_clause; case OMP_LIST_UNIFORM: clause_code = OMP_CLAUSE_UNIFORM; - /* FALLTHROUGH */ + goto add_clause; + case OMP_LIST_USE_DEVICE: + clause_code = OMP_CLAUSE_USE_DEVICE; + goto add_clause; + case OMP_LIST_DEVICE_RESIDENT: + clause_code = OMP_CLAUSE_DEVICE_RESIDENT; + goto add_clause; + case OMP_LIST_CACHE: + clause_code = OMP_CLAUSE__CACHE_; + goto add_clause; + add_clause: omp_clauses = gfc_trans_omp_variable_list (clause_code, n, omp_clauses, @@ -1928,7 +1954,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, tree orig_decl = decl; node4 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node4) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (node4, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (node4) = decl; OMP_CLAUSE_SIZE (node4) = size_int (0); decl = build_fold_indirect_ref (decl); @@ -1938,7 +1964,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, { node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (node3) = decl; OMP_CLAUSE_SIZE (node3) = size_int (0); decl = build_fold_indirect_ref (decl); @@ -1954,12 +1980,12 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, OMP_CLAUSE_DECL (node) = ptr; node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node2) = OMP_CLAUSE_MAP_TO_PSET; + OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET); OMP_CLAUSE_DECL (node2) = decl; OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type); node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (node3) = gfc_conv_descriptor_data_get (decl); OMP_CLAUSE_SIZE (node3) = size_int (0); @@ -2045,7 +2071,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, { node4 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node4) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (node4, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (node4) = decl; OMP_CLAUSE_SIZE (node4) = size_int (0); decl = build_fold_indirect_ref (decl); @@ -2057,12 +2083,12 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, ptr2 = gfc_conv_descriptor_data_get (decl); node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node2) = OMP_CLAUSE_MAP_TO_PSET; + OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET); OMP_CLAUSE_DECL (node2) = decl; OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type); node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (node3) = gfc_conv_descriptor_data_get (decl); } @@ -2077,7 +2103,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, } node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_MAP_KIND (node3) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER); OMP_CLAUSE_DECL (node3) = decl; } ptr2 = fold_convert (sizetype, ptr2); @@ -2087,16 +2113,37 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, switch (n->u.map_op) { case OMP_MAP_ALLOC: - OMP_CLAUSE_MAP_KIND (node) = OMP_CLAUSE_MAP_ALLOC; + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ALLOC); break; case OMP_MAP_TO: - OMP_CLAUSE_MAP_KIND (node) = OMP_CLAUSE_MAP_TO; + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_TO); break; case OMP_MAP_FROM: - OMP_CLAUSE_MAP_KIND (node) = OMP_CLAUSE_MAP_FROM; + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FROM); break; case OMP_MAP_TOFROM: - OMP_CLAUSE_MAP_KIND (node) = OMP_CLAUSE_MAP_TOFROM; + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_TOFROM); + break; + case OMP_MAP_FORCE_ALLOC: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_ALLOC); + break; + case OMP_MAP_FORCE_DEALLOC: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_DEALLOC); + break; + case OMP_MAP_FORCE_TO: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_TO); + break; + case OMP_MAP_FORCE_FROM: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_FROM); + break; + case OMP_MAP_FORCE_TOFROM: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_TOFROM); + break; + case OMP_MAP_FORCE_PRESENT: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_PRESENT); + break; + case OMP_MAP_FORCE_DEVICEPTR: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_DEVICEPTR); break; default: gcc_unreachable (); @@ -2463,6 +2510,111 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, omp_clauses = gfc_trans_add_clause (c, omp_clauses); } + if (clauses->async) + { + c = build_omp_clause (where.lb->location, OMP_CLAUSE_ASYNC); + if (clauses->async_expr) + OMP_CLAUSE_ASYNC_EXPR (c) + = gfc_convert_expr_to_tree (block, clauses->async_expr); + else + OMP_CLAUSE_ASYNC_EXPR (c) = NULL; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->seq) + { + c = build_omp_clause (where.lb->location, OMP_CLAUSE_ORDERED); + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->independent) + { + c = build_omp_clause (where.lb->location, OMP_CLAUSE_INDEPENDENT); + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->wait_list) + { + gfc_expr_list *el; + + for (el = clauses->wait_list; el; el = el->next) + { + c = build_omp_clause (where.lb->location, OMP_CLAUSE_WAIT); + OMP_CLAUSE_DECL (c) = gfc_convert_expr_to_tree (block, el->expr); + OMP_CLAUSE_CHAIN (c) = omp_clauses; + omp_clauses = c; + } + } + if (clauses->num_gangs_expr) + { + tree num_gangs_var + = gfc_convert_expr_to_tree (block, clauses->num_gangs_expr); + c = build_omp_clause (where.lb->location, OMP_CLAUSE_NUM_GANGS); + OMP_CLAUSE_NUM_GANGS_EXPR (c) = num_gangs_var; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->num_workers_expr) + { + tree num_workers_var + = gfc_convert_expr_to_tree (block, clauses->num_workers_expr); + c = build_omp_clause (where.lb->location, OMP_CLAUSE_NUM_WORKERS); + OMP_CLAUSE_NUM_WORKERS_EXPR (c) = num_workers_var; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->vector_length_expr) + { + tree vector_length_var + = gfc_convert_expr_to_tree (block, clauses->vector_length_expr); + c = build_omp_clause (where.lb->location, OMP_CLAUSE_VECTOR_LENGTH); + OMP_CLAUSE_VECTOR_LENGTH_EXPR (c) = vector_length_var; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->vector) + { + if (clauses->vector_expr) + { + tree vector_var + = gfc_convert_expr_to_tree (block, clauses->vector_expr); + c = build_omp_clause (where.lb->location, OMP_CLAUSE_VECTOR); + OMP_CLAUSE_VECTOR_EXPR (c) = vector_var; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + else + { + c = build_omp_clause (where.lb->location, OMP_CLAUSE_VECTOR); + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + } + if (clauses->worker) + { + if (clauses->worker_expr) + { + tree worker_var + = gfc_convert_expr_to_tree (block, clauses->worker_expr); + c = build_omp_clause (where.lb->location, OMP_CLAUSE_WORKER); + OMP_CLAUSE_WORKER_EXPR (c) = worker_var; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + else + { + c = build_omp_clause (where.lb->location, OMP_CLAUSE_WORKER); + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + } + if (clauses->gang) + { + if (clauses->gang_expr) + { + tree gang_var + = gfc_convert_expr_to_tree (block, clauses->gang_expr); + c = build_omp_clause (where.lb->location, OMP_CLAUSE_GANG); + OMP_CLAUSE_GANG_EXPR (c) = gang_var; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + else + { + c = build_omp_clause (where.lb->location, OMP_CLAUSE_GANG); + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + } + return nreverse (omp_clauses); } @@ -2490,6 +2642,115 @@ gfc_trans_omp_code (gfc_code *code, bool force_empty) return stmt; } +/* Trans OpenACC directives. */ +/* parallel, kernels, data and host_data. */ +static tree +gfc_trans_oacc_construct (gfc_code *code) +{ + stmtblock_t block; + tree stmt, oacc_clauses; + enum tree_code construct_code; + + switch (code->op) + { + case EXEC_OACC_PARALLEL: + construct_code = OACC_PARALLEL; + break; + case EXEC_OACC_KERNELS: + construct_code = OACC_KERNELS; + break; + case EXEC_OACC_DATA: + construct_code = OACC_DATA; + break; + case EXEC_OACC_HOST_DATA: + construct_code = OACC_HOST_DATA; + break; + default: + gcc_unreachable (); + } + + gfc_start_block (&block); + oacc_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, + code->loc); + stmt = gfc_trans_omp_code (code->block->next, true); + stmt = build2_loc (input_location, construct_code, void_type_node, stmt, + oacc_clauses); + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + +/* update, enter_data, exit_data, cache. */ +static tree +gfc_trans_oacc_executable_directive (gfc_code *code) +{ + stmtblock_t block; + tree stmt, oacc_clauses; + enum tree_code construct_code; + + switch (code->op) + { + case EXEC_OACC_UPDATE: + construct_code = OACC_UPDATE; + break; + case EXEC_OACC_ENTER_DATA: + construct_code = OACC_ENTER_DATA; + break; + case EXEC_OACC_EXIT_DATA: + construct_code = OACC_EXIT_DATA; + break; + case EXEC_OACC_CACHE: + construct_code = OACC_CACHE; + break; + default: + gcc_unreachable (); + } + + gfc_start_block (&block); + oacc_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, + code->loc); + stmt = build1_loc (input_location, construct_code, void_type_node, + oacc_clauses); + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + +static tree +gfc_trans_oacc_wait_directive (gfc_code *code) +{ + stmtblock_t block; + tree stmt, t; + vec<tree, va_gc> *args; + int nparms = 0; + gfc_expr_list *el; + gfc_omp_clauses *clauses = code->ext.omp_clauses; + location_t loc = input_location; + + for (el = clauses->wait_list; el; el = el->next) + nparms++; + + vec_alloc (args, nparms + 2); + stmt = builtin_decl_explicit (BUILT_IN_GOACC_WAIT); + + gfc_start_block (&block); + + if (clauses->async_expr) + t = gfc_convert_expr_to_tree (&block, clauses->async_expr); + else + t = build_int_cst (integer_type_node, -2); + + args->quick_push (t); + args->quick_push (build_int_cst (integer_type_node, nparms)); + + for (el = clauses->wait_list; el; el = el->next) + args->quick_push (gfc_convert_expr_to_tree (&block, el->expr)); + + stmt = build_call_expr_loc_vec (loc, stmt, args); + gfc_add_expr_to_block (&block, stmt); + + vec_free (args); + + return gfc_finish_block (&block); +} static tree gfc_trans_omp_sections (gfc_code *, gfc_omp_clauses *); static tree gfc_trans_omp_workshare (gfc_code *, gfc_omp_clauses *); @@ -3115,6 +3376,7 @@ gfc_trans_omp_do (gfc_code *code, gfc_exec_op op, stmtblock_t *pblock, case EXEC_OMP_SIMD: stmt = make_node (OMP_SIMD); break; case EXEC_OMP_DO: stmt = make_node (OMP_FOR); break; case EXEC_OMP_DISTRIBUTE: stmt = make_node (OMP_DISTRIBUTE); break; + case EXEC_OACC_LOOP: stmt = make_node (OACC_LOOP); break; default: gcc_unreachable (); } @@ -3129,6 +3391,68 @@ gfc_trans_omp_do (gfc_code *code, gfc_exec_op op, stmtblock_t *pblock, return gfc_finish_block (&block); } +/* parallel loop and kernels loop. */ +static tree +gfc_trans_oacc_combined_directive (gfc_code *code) +{ + stmtblock_t block, *pblock = NULL; + gfc_omp_clauses construct_clauses, loop_clauses; + tree stmt, oacc_clauses = NULL_TREE; + enum tree_code construct_code; + + switch (code->op) + { + case EXEC_OACC_PARALLEL_LOOP: + construct_code = OACC_PARALLEL; + break; + case EXEC_OACC_KERNELS_LOOP: + construct_code = OACC_KERNELS; + break; + default: + gcc_unreachable (); + } + + gfc_start_block (&block); + + memset (&loop_clauses, 0, sizeof (loop_clauses)); + if (code->ext.omp_clauses != NULL) + { + memcpy (&construct_clauses, code->ext.omp_clauses, + sizeof (construct_clauses)); + loop_clauses.collapse = construct_clauses.collapse; + loop_clauses.gang = construct_clauses.gang; + loop_clauses.vector = construct_clauses.vector; + loop_clauses.worker = construct_clauses.worker; + loop_clauses.seq = construct_clauses.seq; + loop_clauses.independent = construct_clauses.independent; + construct_clauses.collapse = 0; + construct_clauses.gang = false; + construct_clauses.vector = false; + construct_clauses.worker = false; + construct_clauses.seq = false; + construct_clauses.independent = false; + oacc_clauses = gfc_trans_omp_clauses (&block, &construct_clauses, + code->loc); + } + if (!loop_clauses.seq) + pblock = █ + else + pushlevel (); + stmt = gfc_trans_omp_do (code, code->op, pblock, &loop_clauses, NULL); + if (TREE_CODE (stmt) != BIND_EXPR) + stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); + else + poplevel (0, 0); + stmt = build2_loc (input_location, construct_code, void_type_node, stmt, + oacc_clauses); + if (code->op == EXEC_OACC_KERNELS_LOOP) + OACC_KERNELS_COMBINED (stmt) = 1; + else + OACC_PARALLEL_COMBINED (stmt) = 1; + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + static tree gfc_trans_omp_flush (void) { @@ -4019,6 +4343,44 @@ gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) } tree +gfc_trans_oacc_declare (stmtblock_t *block, gfc_namespace *ns) +{ + tree oacc_clauses; + oacc_clauses = gfc_trans_omp_clauses (block, ns->oacc_declare_clauses, + ns->oacc_declare_clauses->loc); + return build1_loc (ns->oacc_declare_clauses->loc.lb->location, + OACC_DECLARE, void_type_node, oacc_clauses); +} + +tree +gfc_trans_oacc_directive (gfc_code *code) +{ + switch (code->op) + { + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_KERNELS_LOOP: + return gfc_trans_oacc_combined_directive (code); + case EXEC_OACC_PARALLEL: + case EXEC_OACC_KERNELS: + case EXEC_OACC_DATA: + case EXEC_OACC_HOST_DATA: + return gfc_trans_oacc_construct (code); + case EXEC_OACC_LOOP: + return gfc_trans_omp_do (code, code->op, NULL, code->ext.omp_clauses, + NULL); + case EXEC_OACC_UPDATE: + case EXEC_OACC_CACHE: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: + return gfc_trans_oacc_executable_directive (code); + case EXEC_OACC_WAIT: + return gfc_trans_oacc_wait_directive (code); + default: + gcc_unreachable (); + } +} + +tree gfc_trans_omp_directive (gfc_code *code) { switch (code->op) diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 69a1065..1a4099c 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -1378,6 +1378,14 @@ gfc_trans_block_construct (gfc_code* code) gfc_init_block (&body); exit_label = gfc_build_label_decl (NULL_TREE); code->exit_label = exit_label; + + /* Generate !$ACC DECLARE directive. */ + if (ns->oacc_declare_clauses) + { + tree tmp = gfc_trans_oacc_declare (&body, ns); + gfc_add_expr_to_block (&body, tmp); + } + gfc_add_expr_to_block (&body, gfc_trans_code (ns->code)); gfc_add_expr_to_block (&body, build1_v (LABEL_EXPR, exit_label)); diff --git a/gcc/fortran/trans-stmt.h b/gcc/fortran/trans-stmt.h index 3814fc2..2f2a0b3 100644 --- a/gcc/fortran/trans-stmt.h +++ b/gcc/fortran/trans-stmt.h @@ -65,6 +65,10 @@ tree gfc_trans_deallocate_array (tree); tree gfc_trans_omp_directive (gfc_code *); void gfc_trans_omp_declare_simd (gfc_namespace *); +/* trans-openacc.c */ +tree gfc_trans_oacc_directive (gfc_code *); +tree gfc_trans_oacc_declare (stmtblock_t *block, gfc_namespace *); + /* trans-io.c */ tree gfc_trans_open (gfc_code *); tree gfc_trans_close (gfc_code *); diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index c7aaee8..b749783 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -1900,6 +1900,21 @@ trans_code (gfc_code * code, tree cond) res = gfc_trans_omp_directive (code); break; + case EXEC_OACC_CACHE: + case EXEC_OACC_WAIT: + case EXEC_OACC_UPDATE: + case EXEC_OACC_LOOP: + case EXEC_OACC_HOST_DATA: + case EXEC_OACC_DATA: + case EXEC_OACC_KERNELS: + case EXEC_OACC_KERNELS_LOOP: + case EXEC_OACC_PARALLEL: + case EXEC_OACC_PARALLEL_LOOP: + case EXEC_OACC_ENTER_DATA: + case EXEC_OACC_EXIT_DATA: + res = gfc_trans_oacc_directive (code); + break; + default: gfc_internal_error ("gfc_trans_code(): Bad statement code"); } diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def index 5650155..fdae28d 100644 --- a/gcc/fortran/types.def +++ b/gcc/fortran/types.def @@ -82,6 +82,7 @@ DEF_FUNCTION_TYPE_0 (BT_FN_VOID, BT_VOID) DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTR, BT_VOID, BT_PTR) DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTRPTR, BT_VOID, BT_PTR_PTR) DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VPTR, BT_VOID, BT_VOLATILE_PTR) +DEF_FUNCTION_TYPE_1 (BT_FN_INT_INT, BT_INT, BT_INT) DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT) DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR) DEF_FUNCTION_TYPE_1 (BT_FN_VOID_INT, BT_VOID, BT_INT) @@ -209,3 +210,14 @@ DEF_FUNCTION_TYPE_8 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR, BT_BOOL, BT_UINT, BT_PTR) DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID) + +DEF_FUNCTION_TYPE_VAR_2 (BT_FN_VOID_INT_INT_VAR, BT_VOID, BT_INT, BT_INT) + +DEF_FUNCTION_TYPE_VAR_8 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR, + BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR, + BT_PTR, BT_INT, BT_INT) + +DEF_FUNCTION_TYPE_VAR_12 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR, + BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE, + BT_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT, BT_INT, + BT_INT, BT_INT) @@ -829,7 +829,7 @@ proper position among the other output files. */ "%X %{o*} %{e*} %{N} %{n} %{r}\ %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} " VTABLE_VERIFICATION_SPEC " \ %{static:} %{L*} %(mfwrap) %(link_libgcc) " SANITIZER_EARLY_SPEC " %o\ - %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\ + %{fopenacc|fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\ %{fcilkplus:%:include(libcilkrts.spec)%(link_cilkrts)}\ %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\ %(mflib) " STACK_SPLIT_SPEC "\ @@ -990,7 +990,8 @@ static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS; /* Linking to libgomp implies pthreads. This is particularly important for targets that use different start files and suchlike. */ #ifndef GOMP_SELF_SPECS -#define GOMP_SELF_SPECS "%{fopenmp|ftree-parallelize-loops=*: -pthread}" +#define GOMP_SELF_SPECS "%{fopenacc|fopenmp|ftree-parallelize-loops=*: " \ + "-pthread}" #endif /* Likewise for -fgnu-tm. */ diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 21e98c6..2f9671f 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1151,18 +1151,21 @@ dump_gimple_omp_for (pretty_printer *buffer, gomp_for *gs, int spc, int flags) case GF_OMP_FOR_KIND_FOR: kind = ""; break; - case GF_OMP_FOR_KIND_SIMD: - kind = " simd"; - break; - case GF_OMP_FOR_KIND_CILKSIMD: - kind = " cilksimd"; - break; case GF_OMP_FOR_KIND_DISTRIBUTE: kind = " distribute"; break; case GF_OMP_FOR_KIND_CILKFOR: kind = " _Cilk_for"; break; + case GF_OMP_FOR_KIND_OACC_LOOP: + kind = " oacc_loop"; + break; + case GF_OMP_FOR_KIND_SIMD: + kind = " simd"; + break; + case GF_OMP_FOR_KIND_CILKSIMD: + kind = " cilksimd"; + break; default: gcc_unreachable (); } @@ -1188,17 +1191,20 @@ dump_gimple_omp_for (pretty_printer *buffer, gomp_for *gs, int spc, int flags) case GF_OMP_FOR_KIND_FOR: pp_string (buffer, "#pragma omp for"); break; + case GF_OMP_FOR_KIND_DISTRIBUTE: + pp_string (buffer, "#pragma omp distribute"); + break; + case GF_OMP_FOR_KIND_CILKFOR: + break; + case GF_OMP_FOR_KIND_OACC_LOOP: + pp_string (buffer, "#pragma acc loop"); + break; case GF_OMP_FOR_KIND_SIMD: pp_string (buffer, "#pragma omp simd"); break; case GF_OMP_FOR_KIND_CILKSIMD: pp_string (buffer, "#pragma simd"); break; - case GF_OMP_FOR_KIND_DISTRIBUTE: - pp_string (buffer, "#pragma omp distribute"); - break; - case GF_OMP_FOR_KIND_CILKFOR: - break; default: gcc_unreachable (); } @@ -1344,6 +1350,21 @@ dump_gimple_omp_target (pretty_printer *buffer, gomp_target *gs, case GF_OMP_TARGET_KIND_UPDATE: kind = " update"; break; + case GF_OMP_TARGET_KIND_OACC_KERNELS: + kind = " oacc_kernels"; + break; + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + kind = " oacc_parallel"; + break; + case GF_OMP_TARGET_KIND_OACC_DATA: + kind = " oacc_data"; + break; + case GF_OMP_TARGET_KIND_OACC_UPDATE: + kind = " oacc_update"; + break; + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + kind = " oacc_enter_exit_data"; + break; default: gcc_unreachable (); } @@ -1352,7 +1373,9 @@ dump_gimple_omp_target (pretty_printer *buffer, gomp_target *gs, dump_gimple_fmt (buffer, spc, flags, "%G%s <%+BODY <%S>%nCLAUSES <", gs, kind, gimple_omp_body (gs)); dump_omp_clauses (buffer, gimple_omp_target_clauses (gs), spc, flags); - dump_gimple_fmt (buffer, spc, flags, " >"); + dump_gimple_fmt (buffer, spc, flags, " >, %T, %T%n>", + gimple_omp_target_child_fn (gs), + gimple_omp_target_data_arg (gs)); } else { @@ -1364,16 +1387,28 @@ dump_gimple_omp_target (pretty_printer *buffer, gomp_target *gs, pp_string (buffer, " [child fn: "); dump_generic_node (buffer, gimple_omp_target_child_fn (gs), spc, flags, false); - pp_right_bracket (buffer); + pp_string (buffer, " ("); + if (gimple_omp_target_data_arg (gs)) + dump_generic_node (buffer, gimple_omp_target_data_arg (gs), + spc, flags, false); + else + pp_string (buffer, "???"); + pp_string (buffer, ")]"); } - if (!gimple_seq_empty_p (gimple_omp_body (gs))) + gimple_seq body = gimple_omp_body (gs); + if (body && gimple_code (gimple_seq_first_stmt (body)) != GIMPLE_BIND) { newline_and_indent (buffer, spc + 2); - pp_character (buffer, '{'); + pp_left_brace (buffer); pp_newline (buffer); - dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + dump_gimple_seq (buffer, body, spc + 4, flags); newline_and_indent (buffer, spc + 2); - pp_character (buffer, '}'); + pp_right_brace (buffer); + } + else if (body) + { + pp_newline (buffer); + dump_gimple_seq (buffer, body, spc + 2, flags); } } } diff --git a/gcc/gimple.c b/gcc/gimple.c index 9eb7b14..caa1cbd 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -872,8 +872,7 @@ gimple_build_omp_critical (gimple_seq body, tree name) BODY is sequence of statements inside the for loop. KIND is the `for' variant. - CLAUSES, are any of the OMP loop construct's clauses: private, firstprivate, - lastprivate, reductions, ordered, schedule, and nowait. + CLAUSES, are any of the construct's clauses. COLLAPSE is the collapse count. PRE_BODY is the sequence of statements that are loop invariant. */ @@ -1088,7 +1087,8 @@ gimple_build_omp_single (gimple_seq body, tree clauses) /* Build a GIMPLE_OMP_TARGET statement. BODY is the sequence of statements that will be executed. - CLAUSES are any of the OMP target construct's clauses. */ + KIND is the kind of the region. + CLAUSES are any of the construct's clauses. */ gomp_target * gimple_build_omp_target (gimple_seq body, int kind, tree clauses) diff --git a/gcc/gimple.def b/gcc/gimple.def index 0c76ed0..96602df 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -243,6 +243,9 @@ DEFGSCODE(GIMPLE_OMP_CRITICAL, "gimple_omp_critical", GSS_OMP_CRITICAL) for (INDEX = INITIAL; INDEX COND FINAL; INDEX {+=,-=} INCR) BODY + Likewise for: + #pragma acc loop [clause1 ... clauseN] + BODY is the loop body. CLAUSES is the list of clauses. @@ -269,7 +272,7 @@ DEFGSCODE(GIMPLE_OMP_CRITICAL, "gimple_omp_critical", GSS_OMP_CRITICAL) INITIAL, FINAL and INCR are required to be loop invariant integer expressions that are evaluated without any synchronization. The evaluation order, frequency of evaluation and side-effects are - unspecified by the standard. */ + unspecified by the standards. */ DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_for", GSS_OMP_FOR) /* GIMPLE_OMP_MASTER <BODY> represents #pragma omp master. @@ -354,11 +357,12 @@ DEFGSCODE(GIMPLE_OMP_SECTIONS_SWITCH, "gimple_omp_sections_switch", GSS_BASE) DEFGSCODE(GIMPLE_OMP_SINGLE, "gimple_omp_single", GSS_OMP_SINGLE_LAYOUT) /* GIMPLE_OMP_TARGET <BODY, CLAUSES, CHILD_FN> represents + #pragma acc {kernels,parallel,data,enter data,exit data,update} #pragma omp target {,data,update} - BODY is the sequence of statements inside the target construct - (NULL for target update). + BODY is the sequence of statements inside the construct + (NULL for some variants). CLAUSES is an OMP_CLAUSE chain holding the associated clauses. - CHILD_FN is set when outlining the body of the target region. + CHILD_FN is set when outlining the body of the offloaded region. All the statements in BODY are moved into this newly created function when converting OMP constructs into low-GIMPLE. DATA_ARG is a vec of 3 local variables in the parent function diff --git a/gcc/gimple.h b/gcc/gimple.h index d70e567..769bad0 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -89,20 +89,26 @@ enum gf_mask { GF_CALL_CTRL_ALTERING = 1 << 7, GF_CALL_WITH_BOUNDS = 1 << 8, GF_OMP_PARALLEL_COMBINED = 1 << 0, - GF_OMP_FOR_KIND_MASK = 7 << 0, + GF_OMP_FOR_KIND_MASK = (1 << 3) - 1, GF_OMP_FOR_KIND_FOR = 0, GF_OMP_FOR_KIND_DISTRIBUTE = 1, GF_OMP_FOR_KIND_CILKFOR = 2, + GF_OMP_FOR_KIND_OACC_LOOP = 3, /* Flag for SIMD variants of OMP_FOR kinds. */ GF_OMP_FOR_SIMD = 1 << 2, GF_OMP_FOR_KIND_SIMD = GF_OMP_FOR_SIMD | 0, GF_OMP_FOR_KIND_CILKSIMD = GF_OMP_FOR_SIMD | 1, GF_OMP_FOR_COMBINED = 1 << 3, GF_OMP_FOR_COMBINED_INTO = 1 << 4, - GF_OMP_TARGET_KIND_MASK = (1 << 2) - 1, + GF_OMP_TARGET_KIND_MASK = (1 << 3) - 1, GF_OMP_TARGET_KIND_REGION = 0, GF_OMP_TARGET_KIND_DATA = 1, GF_OMP_TARGET_KIND_UPDATE = 2, + GF_OMP_TARGET_KIND_OACC_PARALLEL = 3, + GF_OMP_TARGET_KIND_OACC_KERNELS = 4, + GF_OMP_TARGET_KIND_OACC_DATA = 5, + GF_OMP_TARGET_KIND_OACC_UPDATE = 6, + GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA = 7, /* True on an GIMPLE_OMP_RETURN statement if the return does not require a thread synchronization via some sort of barrier. The exact barrier @@ -291,7 +297,7 @@ struct GTY((tag("GSS_CALL"))) }; -/* OpenMP statements (#pragma omp). */ +/* OMP statements. */ struct GTY((tag("GSS_OMP"))) gimple_statement_omp : public gimple_statement_base @@ -552,7 +558,8 @@ struct GTY((tag("GSS_OMP_FOR"))) }; -/* GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TARGET */ +/* GIMPLE_OMP_PARALLEL, GIMPLE_OMP_TARGET, GIMPLE_OMP_TASK */ + struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT"))) gimple_statement_omp_parallel_layout : public gimple_statement_omp { @@ -580,7 +587,6 @@ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT"))) || stmt->code == GIMPLE_OMP_TASK. */ }; - /* GIMPLE_OMP_PARALLEL */ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT"))) gomp_parallel : public gimple_statement_omp_taskreg @@ -589,6 +595,7 @@ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT"))) stmt->code == GIMPLE_OMP_PARALLEL. */ }; +/* GIMPLE_OMP_TARGET */ struct GTY((tag("GSS_OMP_PARALLEL_LAYOUT"))) gomp_target : public gimple_statement_omp_parallel_layout { @@ -4409,7 +4416,7 @@ gimple_omp_critical_set_name (gomp_critical *crit_stmt, tree name) } -/* Return the kind of OMP for statemement. */ +/* Return the kind of the OMP_FOR statemement G. */ static inline int gimple_omp_for_kind (const_gimple g) @@ -4419,7 +4426,7 @@ gimple_omp_for_kind (const_gimple g) } -/* Set the OMP for kind. */ +/* Set the kind of the OMP_FOR statement G. */ static inline void gimple_omp_for_set_kind (gomp_for *g, int kind) @@ -4429,7 +4436,7 @@ gimple_omp_for_set_kind (gomp_for *g, int kind) } -/* Return true if OMP for statement G has the +/* Return true if OMP_FOR statement G has the GF_OMP_FOR_COMBINED flag set. */ static inline bool @@ -4440,8 +4447,8 @@ gimple_omp_for_combined_p (const_gimple g) } -/* Set the GF_OMP_FOR_COMBINED field in G depending on the boolean - value of COMBINED_P. */ +/* Set the GF_OMP_FOR_COMBINED field in the OMP_FOR statement G depending on + the boolean value of COMBINED_P. */ static inline void gimple_omp_for_set_combined_p (gomp_for *g, bool combined_p) @@ -4453,7 +4460,7 @@ gimple_omp_for_set_combined_p (gomp_for *g, bool combined_p) } -/* Return true if OMP for statement G has the +/* Return true if the OMP_FOR statement G has the GF_OMP_FOR_COMBINED_INTO flag set. */ static inline bool @@ -4464,8 +4471,8 @@ gimple_omp_for_combined_into_p (const_gimple g) } -/* Set the GF_OMP_FOR_COMBINED_INTO field in G depending on the boolean - value of COMBINED_P. */ +/* Set the GF_OMP_FOR_COMBINED_INTO field in the OMP_FOR statement G depending + on the boolean value of COMBINED_P. */ static inline void gimple_omp_for_set_combined_into_p (gomp_for *g, bool combined_p) @@ -4477,7 +4484,7 @@ gimple_omp_for_set_combined_into_p (gomp_for *g, bool combined_p) } -/* Return the clauses associated with OMP_FOR GS. */ +/* Return the clauses associated with the OMP_FOR statement GS. */ static inline tree gimple_omp_for_clauses (const_gimple gs) @@ -4487,7 +4494,8 @@ gimple_omp_for_clauses (const_gimple gs) } -/* Return a pointer to the OMP_FOR GS. */ +/* Return a pointer to the clauses associated with the OMP_FOR statement + GS. */ static inline tree * gimple_omp_for_clauses_ptr (gimple gs) @@ -4497,7 +4505,8 @@ gimple_omp_for_clauses_ptr (gimple gs) } -/* Set CLAUSES to be the list of clauses associated with OMP_FOR GS. */ +/* Set CLAUSES to be the list of clauses associated with the OMP_FOR statement + GS. */ static inline void gimple_omp_for_set_clauses (gimple gs, tree clauses) @@ -4507,7 +4516,7 @@ gimple_omp_for_set_clauses (gimple gs, tree clauses) } -/* Get the collapse count of OMP_FOR GS. */ +/* Get the collapse count of the OMP_FOR statement GS. */ static inline size_t gimple_omp_for_collapse (gimple gs) @@ -4517,7 +4526,30 @@ gimple_omp_for_collapse (gimple gs) } -/* Return the index variable for OMP_FOR GS. */ +/* Return the condition code associated with the OMP_FOR statement GS. */ + +static inline enum tree_code +gimple_omp_for_cond (const_gimple gs, size_t i) +{ + const gomp_for *omp_for_stmt = as_a <const gomp_for *> (gs); + gcc_gimple_checking_assert (i < omp_for_stmt->collapse); + return omp_for_stmt->iter[i].cond; +} + + +/* Set COND to be the condition code for the OMP_FOR statement GS. */ + +static inline void +gimple_omp_for_set_cond (gimple gs, size_t i, enum tree_code cond) +{ + gomp_for *omp_for_stmt = as_a <gomp_for *> (gs); + gcc_gimple_checking_assert (TREE_CODE_CLASS (cond) == tcc_comparison + && i < omp_for_stmt->collapse); + omp_for_stmt->iter[i].cond = cond; +} + + +/* Return the index variable for the OMP_FOR statement GS. */ static inline tree gimple_omp_for_index (const_gimple gs, size_t i) @@ -4528,7 +4560,7 @@ gimple_omp_for_index (const_gimple gs, size_t i) } -/* Return a pointer to the index variable for OMP_FOR GS. */ +/* Return a pointer to the index variable for the OMP_FOR statement GS. */ static inline tree * gimple_omp_for_index_ptr (gimple gs, size_t i) @@ -4539,7 +4571,7 @@ gimple_omp_for_index_ptr (gimple gs, size_t i) } -/* Set INDEX to be the index variable for OMP_FOR GS. */ +/* Set INDEX to be the index variable for the OMP_FOR statement GS. */ static inline void gimple_omp_for_set_index (gimple gs, size_t i, tree index) @@ -4550,7 +4582,7 @@ gimple_omp_for_set_index (gimple gs, size_t i, tree index) } -/* Return the initial value for OMP_FOR GS. */ +/* Return the initial value for the OMP_FOR statement GS. */ static inline tree gimple_omp_for_initial (const_gimple gs, size_t i) @@ -4561,7 +4593,7 @@ gimple_omp_for_initial (const_gimple gs, size_t i) } -/* Return a pointer to the initial value for OMP_FOR GS. */ +/* Return a pointer to the initial value for the OMP_FOR statement GS. */ static inline tree * gimple_omp_for_initial_ptr (gimple gs, size_t i) @@ -4572,7 +4604,7 @@ gimple_omp_for_initial_ptr (gimple gs, size_t i) } -/* Set INITIAL to be the initial value for OMP_FOR GS. */ +/* Set INITIAL to be the initial value for the OMP_FOR statement GS. */ static inline void gimple_omp_for_set_initial (gimple gs, size_t i, tree initial) @@ -4583,7 +4615,7 @@ gimple_omp_for_set_initial (gimple gs, size_t i, tree initial) } -/* Return the final value for OMP_FOR GS. */ +/* Return the final value for the OMP_FOR statement GS. */ static inline tree gimple_omp_for_final (const_gimple gs, size_t i) @@ -4594,7 +4626,7 @@ gimple_omp_for_final (const_gimple gs, size_t i) } -/* Return a pointer to the final value for OMP_FOR GS. */ +/* Return a pointer to the final value for the OMP_FOR statement GS. */ static inline tree * gimple_omp_for_final_ptr (gimple gs, size_t i) @@ -4605,7 +4637,7 @@ gimple_omp_for_final_ptr (gimple gs, size_t i) } -/* Set FINAL to be the final value for OMP_FOR GS. */ +/* Set FINAL to be the final value for the OMP_FOR statement GS. */ static inline void gimple_omp_for_set_final (gimple gs, size_t i, tree final) @@ -4616,7 +4648,7 @@ gimple_omp_for_set_final (gimple gs, size_t i, tree final) } -/* Return the increment value for OMP_FOR GS. */ +/* Return the increment value for the OMP_FOR statement GS. */ static inline tree gimple_omp_for_incr (const_gimple gs, size_t i) @@ -4627,7 +4659,7 @@ gimple_omp_for_incr (const_gimple gs, size_t i) } -/* Return a pointer to the increment value for OMP_FOR GS. */ +/* Return a pointer to the increment value for the OMP_FOR statement GS. */ static inline tree * gimple_omp_for_incr_ptr (gimple gs, size_t i) @@ -4638,7 +4670,7 @@ gimple_omp_for_incr_ptr (gimple gs, size_t i) } -/* Set INCR to be the increment value for OMP_FOR GS. */ +/* Set INCR to be the increment value for the OMP_FOR statement GS. */ static inline void gimple_omp_for_set_incr (gimple gs, size_t i, tree incr) @@ -5109,7 +5141,7 @@ gimple_omp_target_set_clauses (gomp_target *omp_target_stmt, } -/* Return the kind of OMP target statemement. */ +/* Return the kind of the OMP_TARGET G. */ static inline int gimple_omp_target_kind (const_gimple g) @@ -5119,7 +5151,7 @@ gimple_omp_target_kind (const_gimple g) } -/* Set the OMP target kind. */ +/* Set the kind of the OMP_TARGET G. */ static inline void gimple_omp_target_set_kind (gomp_target *g, int kind) @@ -5279,29 +5311,6 @@ gimple_omp_sections_set_control (gimple gs, tree control) } -/* Set COND to be the condition code for OMP_FOR GS. */ - -static inline void -gimple_omp_for_set_cond (gimple gs, size_t i, enum tree_code cond) -{ - gomp_for *omp_for_stmt = as_a <gomp_for *> (gs); - gcc_gimple_checking_assert (TREE_CODE_CLASS (cond) == tcc_comparison - && i < omp_for_stmt->collapse); - omp_for_stmt->iter[i].cond = cond; -} - - -/* Return the condition code associated with OMP_FOR GS. */ - -static inline enum tree_code -gimple_omp_for_cond (const_gimple gs, size_t i) -{ - const gomp_for *omp_for_stmt = as_a <const gomp_for *> (gs); - gcc_gimple_checking_assert (i < omp_for_stmt->collapse); - return omp_for_stmt->iter[i].cond; -} - - /* Set the value being stored in an atomic store. */ static inline void @@ -5547,7 +5556,7 @@ gimple_return_set_retbnd (gimple gs, tree retval) } -/* Returns true when the gimple statement STMT is any of the OpenMP types. */ +/* Returns true when the gimple statement STMT is any of the OMP types. */ #define CASE_GIMPLE_OMP \ case GIMPLE_OMP_PARALLEL: \ @@ -5580,6 +5589,64 @@ is_gimple_omp (const_gimple stmt) } } +/* Return true if the OMP gimple statement STMT is any of the OpenACC types + specifically. */ + +static inline bool +is_gimple_omp_oacc (const_gimple stmt) +{ + gcc_assert (is_gimple_omp (stmt)); + switch (gimple_code (stmt)) + { + case GIMPLE_OMP_FOR: + switch (gimple_omp_for_kind (stmt)) + { + case GF_OMP_FOR_KIND_OACC_LOOP: + return true; + default: + return false; + } + case GIMPLE_OMP_TARGET: + switch (gimple_omp_target_kind (stmt)) + { + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: + case GF_OMP_TARGET_KIND_OACC_DATA: + case GF_OMP_TARGET_KIND_OACC_UPDATE: + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + return true; + default: + return false; + } + default: + return false; + } +} + + +/* Return true if the OMP gimple statement STMT is offloaded. */ + +static inline bool +is_gimple_omp_offloaded (const_gimple stmt) +{ + gcc_assert (is_gimple_omp (stmt)); + switch (gimple_code (stmt)) + { + case GIMPLE_OMP_TARGET: + switch (gimple_omp_target_kind (stmt)) + { + case GF_OMP_TARGET_KIND_REGION: + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: + return true; + default: + return false; + } + default: + return false; + } +} + /* Returns TRUE if statement G is a GIMPLE_NOP. */ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 2472d86..3a34f92 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -86,6 +86,7 @@ along with GCC; see the file COPYING3. If not see #include "omp-low.h" #include "gimple-low.h" #include "cilk.h" +#include "gomp-constants.h" #include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name */ #include "tree-pass.h" /* FIXME: only for PROP_gimple_any */ @@ -106,7 +107,10 @@ enum gimplify_omp_var_data GOVD_PRIVATE_OUTER_REF = 1024, GOVD_LINEAR = 2048, GOVD_ALIGNED = 4096, + + /* Flag for GOVD_MAP: don't copy back. */ GOVD_MAP_TO_ONLY = 8192, + GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR | GOVD_LOCAL) @@ -122,7 +126,9 @@ enum omp_region_type ORT_TASK = 4, ORT_UNTIED_TASK = 5, ORT_TEAMS = 8, + /* Data region. */ ORT_TARGET_DATA = 16, + /* Data region with offloading. */ ORT_TARGET = 32 }; @@ -1560,9 +1566,10 @@ gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p) struct gimplify_ctx *ctxp; glabel *label_stmt; - /* Invalid OpenMP programs can play Duff's Device type games with + /* Invalid programs can play Duff's Device type games with, for example, #pragma omp parallel. At least in the C front end, we don't - detect such invalid branches until after gimplification. */ + detect such invalid branches until after gimplification, in the + diagnose_omp_blocks pass. */ for (ctxp = gimplify_ctxp; ; ctxp = ctxp->prev_context) if (ctxp->case_labels.exists ()) break; @@ -1791,7 +1798,7 @@ gimplify_var_or_parm_decl (tree *expr_p) return GS_ERROR; } - /* When within an OpenMP context, notice uses of variables. */ + /* When within an OMP context, notice uses of variables. */ if (gimplify_omp_ctxp && omp_notice_variable (gimplify_omp_ctxp, decl, true)) return GS_ALL_DONE; @@ -2260,7 +2267,7 @@ gimplify_arg (tree *arg_p, gimple_seq *pre_p, location_t call_location) return gimplify_expr (arg_p, pre_p, NULL, test, fb); } -/* Don't fold STMT inside ORT_TARGET, because it can break code by adding decl +/* Don't fold inside offloading regions: it can break code by adding decl references that weren't in the source. We'll do it during omplower pass instead. */ @@ -4451,11 +4458,21 @@ is_gimple_stmt (tree t) case CATCH_EXPR: case ASM_EXPR: case STATEMENT_LIST: + case OACC_PARALLEL: + case OACC_KERNELS: + case OACC_DATA: + case OACC_HOST_DATA: + case OACC_DECLARE: + case OACC_UPDATE: + case OACC_ENTER_DATA: + case OACC_EXIT_DATA: + case OACC_CACHE: case OMP_PARALLEL: case OMP_FOR: case OMP_SIMD: case CILK_SIMD: case OMP_DISTRIBUTE: + case OACC_LOOP: case OMP_SECTIONS: case OMP_SECTION: case OMP_SINGLE: @@ -5582,7 +5599,7 @@ omp_firstprivatize_type_sizes (struct gimplify_omp_ctx *ctx, tree type) lang_hooks.types.omp_firstprivatize_type_sizes (ctx, type); } -/* Add an entry for DECL in the OpenMP context CTX with FLAGS. */ +/* Add an entry for DECL in the OMP context CTX with FLAGS. */ static void omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) @@ -5627,9 +5644,12 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) copy into or out of the context. */ if (!(flags & GOVD_LOCAL)) { - nflags = flags & GOVD_MAP - ? GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT - : flags & GOVD_PRIVATE ? GOVD_PRIVATE : GOVD_FIRSTPRIVATE; + if (flags & GOVD_MAP) + nflags = GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT; + else if (flags & GOVD_PRIVATE) + nflags = GOVD_PRIVATE; + else + nflags = GOVD_FIRSTPRIVATE; nflags |= flags & GOVD_SEEN; t = DECL_VALUE_EXPR (decl); gcc_assert (TREE_CODE (t) == INDIRECT_REF); @@ -5683,7 +5703,7 @@ omp_add_variable (struct gimplify_omp_ctx *ctx, tree decl, unsigned int flags) splay_tree_insert (ctx->variables, (splay_tree_key)decl, flags); } -/* Notice a threadprivate variable DECL used in OpenMP context CTX. +/* Notice a threadprivate variable DECL used in OMP context CTX. This just prints out diagnostics about threadprivate variable uses in untied tasks. If DECL2 is non-NULL, prevent this warning on that variable. */ @@ -5725,7 +5745,7 @@ omp_notice_threadprivate_variable (struct gimplify_omp_ctx *ctx, tree decl, return false; } -/* Record the fact that DECL was used within the OpenMP context CTX. +/* Record the fact that DECL was used within the OMP context CTX. IN_CODE is true when real code uses DECL, and false when we should merely emit default(none) errors. Return true if DECL is going to be remapped and thus DECL shouldn't be gimplified into its @@ -6006,7 +6026,7 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate) return false; } -/* Scan the OpenMP clauses in *LIST_P, installing mappings into a new +/* Scan the OMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ static void @@ -6117,6 +6137,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + case OMP_CLAUSE__CACHE_: decl = OMP_CLAUSE_DECL (c); if (error_operand_p (decl)) { @@ -6282,15 +6303,35 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE__CILK_FOR_COUNT_: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: + case OMP_CLAUSE_GANG: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, is_gimple_val, fb_rvalue) == GS_ERROR) remove = true; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_GANG + && gimplify_expr (&OMP_CLAUSE_OPERAND (c, 1), pre_p, NULL, + is_gimple_val, fb_rvalue) == GS_ERROR) + remove = true; + break; + + case OMP_CLAUSE_DEVICE_RESIDENT: + case OMP_CLAUSE_USE_DEVICE: + case OMP_CLAUSE_INDEPENDENT: + remove = true; break; case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_UNTIED: case OMP_CLAUSE_COLLAPSE: + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_SEQ: case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: @@ -6411,9 +6452,10 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1; else if (code == OMP_CLAUSE_MAP) { - OMP_CLAUSE_MAP_KIND (clause) = flags & GOVD_MAP_TO_ONLY - ? OMP_CLAUSE_MAP_TO - : OMP_CLAUSE_MAP_TOFROM; + OMP_CLAUSE_SET_MAP_KIND (clause, + flags & GOVD_MAP_TO_ONLY + ? GOMP_MAP_TO + : GOMP_MAP_TOFROM); if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) { @@ -6434,7 +6476,7 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) OMP_CLAUSE_MAP); OMP_CLAUSE_DECL (nc) = decl; OMP_CLAUSE_SIZE (nc) = size_zero_node; - OMP_CLAUSE_MAP_KIND (nc) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause); OMP_CLAUSE_CHAIN (clause) = nc; } @@ -6584,8 +6626,13 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) remove = true; else if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST - && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_POINTER) + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER) { + /* For GOMP_MAP_FORCE_DEVICEPTR, we'll never enter here, because + for these, TREE_CODE (DECL_SIZE (decl)) will always be + INTEGER_CST. */ + gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); + tree decl2 = DECL_VALUE_EXPR (decl); gcc_assert (TREE_CODE (decl2) == INDIRECT_REF); decl2 = TREE_OPERAND (decl2, 0); @@ -6603,7 +6650,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) OMP_CLAUSE_MAP); OMP_CLAUSE_DECL (nc) = decl; OMP_CLAUSE_SIZE (nc) = size_zero_node; - OMP_CLAUSE_MAP_KIND (nc) = OMP_CLAUSE_MAP_POINTER; + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER); OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c); OMP_CLAUSE_CHAIN (c) = nc; c = nc; @@ -6614,6 +6661,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: + case OMP_CLAUSE__CACHE_: decl = OMP_CLAUSE_DECL (c); if (!DECL_P (decl)) break; @@ -6659,6 +6707,19 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_DEPEND: case OMP_CLAUSE__CILK_FOR_COUNT_: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_DEVICE_RESIDENT: + case OMP_CLAUSE_USE_DEVICE: + case OMP_CLAUSE_INDEPENDENT: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: + case OMP_CLAUSE_GANG: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_SEQ: break; default: @@ -6681,6 +6742,21 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p) delete_omp_context (ctx); } +/* Gimplify OACC_CACHE. */ + +static void +gimplify_oacc_cache (tree *expr_p, gimple_seq *pre_p) +{ + tree expr = *expr_p; + + gimplify_scan_omp_clauses (&OACC_CACHE_CLAUSES (expr), pre_p, ORT_WORKSHARE); + gimplify_adjust_omp_clauses (pre_p, &OACC_CACHE_CLAUSES (expr)); + + /* TODO: Do something sensible with this information. */ + + *expr_p = NULL_TREE; +} + /* Gimplify the contents of an OMP_PARALLEL statement. This involves gimplification of the body, as well as scanning the body for used variables. We need to do this scan now, because variable-sized @@ -6795,8 +6871,22 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) orig_for_stmt = for_stmt = *expr_p; - simd = (TREE_CODE (for_stmt) == OMP_SIMD - || TREE_CODE (for_stmt) == CILK_SIMD); + switch (TREE_CODE (for_stmt)) + { + case OMP_FOR: + case CILK_FOR: + case OMP_DISTRIBUTE: + case OACC_LOOP: + simd = false; + break; + case OMP_SIMD: + case CILK_SIMD: + simd = true; + break; + default: + gcc_unreachable (); + } + gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, simd ? ORT_SIMD : ORT_WORKSHARE); if (TREE_CODE (for_stmt) == OMP_DISTRIBUTE) @@ -6832,6 +6922,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) if (OMP_FOR_INIT (for_stmt) == NULL_TREE) { + gcc_assert (TREE_CODE (for_stmt) != OACC_LOOP); for_stmt = walk_tree (&OMP_FOR_BODY (for_stmt), find_combined_omp_for, NULL, NULL); gcc_assert (for_stmt != NULL_TREE); @@ -7133,6 +7224,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case CILK_SIMD: kind = GF_OMP_FOR_KIND_CILKSIMD; break; case CILK_FOR: kind = GF_OMP_FOR_KIND_CILKFOR; break; case OMP_DISTRIBUTE: kind = GF_OMP_FOR_KIND_DISTRIBUTE; break; + case OACC_LOOP: kind = GF_OMP_FOR_KIND_OACC_LOOP; break; default: gcc_unreachable (); } @@ -7173,9 +7265,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) return GS_ALL_DONE; } -/* Gimplify the gross structure of other OpenMP constructs. - In particular, OMP_SECTIONS, OMP_SINGLE, OMP_TARGET, OMP_TARGET_DATA - and OMP_TEAMS. */ +/* Gimplify the gross structure of several OMP constructs. */ static void gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) @@ -7183,16 +7273,20 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) tree expr = *expr_p; gimple stmt; gimple_seq body = NULL; - enum omp_region_type ort = ORT_WORKSHARE; + enum omp_region_type ort; switch (TREE_CODE (expr)) { case OMP_SECTIONS: case OMP_SINGLE: + ort = ORT_WORKSHARE; break; + case OACC_KERNELS: + case OACC_PARALLEL: case OMP_TARGET: ort = ORT_TARGET; break; + case OACC_DATA: case OMP_TARGET_DATA: ort = ORT_TARGET_DATA; break; @@ -7213,9 +7307,21 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) pop_gimplify_context (NULL); if (ort == ORT_TARGET_DATA) { - gimple_seq cleanup = NULL; - tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TARGET_END_DATA); + enum built_in_function end_ix; + switch (TREE_CODE (expr)) + { + case OACC_DATA: + end_ix = BUILT_IN_GOACC_DATA_END; + break; + case OMP_TARGET_DATA: + end_ix = BUILT_IN_GOMP_TARGET_END_DATA; + break; + default: + gcc_unreachable (); + } + tree fn = builtin_decl_explicit (end_ix); g = gimple_build_call (fn, 0); + gimple_seq cleanup = NULL; gimple_seq_add_stmt (&cleanup, g); g = gimple_build_try (body, cleanup, GIMPLE_TRY_FINALLY); body = NULL; @@ -7228,6 +7334,18 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) switch (TREE_CODE (expr)) { + case OACC_DATA: + stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_DATA, + OMP_CLAUSES (expr)); + break; + case OACC_KERNELS: + stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_KERNELS, + OMP_CLAUSES (expr)); + break; + case OACC_PARALLEL: + stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_OACC_PARALLEL, + OMP_CLAUSES (expr)); + break; case OMP_SECTIONS: stmt = gimple_build_omp_sections (body, OMP_CLAUSES (expr)); break; @@ -7253,19 +7371,40 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) *expr_p = NULL_TREE; } -/* Gimplify the gross structure of OpenMP target update construct. */ +/* Gimplify the gross structure of OpenACC enter/exit data, update, and OpenMP + target update constructs. */ static void gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) { - tree expr = *expr_p; + tree expr = *expr_p, clauses; + int kind; gomp_target *stmt; - gimplify_scan_omp_clauses (&OMP_TARGET_UPDATE_CLAUSES (expr), pre_p, - ORT_WORKSHARE); - gimplify_adjust_omp_clauses (pre_p, &OMP_TARGET_UPDATE_CLAUSES (expr)); - stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_UPDATE, - OMP_TARGET_UPDATE_CLAUSES (expr)); + switch (TREE_CODE (expr)) + { + case OACC_ENTER_DATA: + clauses = OACC_ENTER_DATA_CLAUSES (expr); + kind = GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA; + break; + case OACC_EXIT_DATA: + clauses = OACC_EXIT_DATA_CLAUSES (expr); + kind = GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA; + break; + case OACC_UPDATE: + clauses = OACC_UPDATE_CLAUSES (expr); + kind = GF_OMP_TARGET_KIND_OACC_UPDATE; + break; + case OMP_TARGET_UPDATE: + clauses = OMP_TARGET_UPDATE_CLAUSES (expr); + kind = GF_OMP_TARGET_KIND_UPDATE; + break; + default: + gcc_unreachable (); + } + gimplify_scan_omp_clauses (&clauses, pre_p, ORT_WORKSHARE); + gimplify_adjust_omp_clauses (pre_p, &clauses); + stmt = gimple_build_omp_target (NULL, kind, clauses); gimplify_seq_add_stmt (pre_p, stmt); *expr_p = NULL_TREE; @@ -7445,7 +7584,7 @@ gimplify_transaction (tree *expr_p, gimple_seq *pre_p) int subcode = 0; /* Wrap the transaction body in a BIND_EXPR so we have a context - where to put decls for OpenMP. */ + where to put decls for OMP. */ if (TREE_CODE (tbody) != BIND_EXPR) { tree bind = build3 (BIND_EXPR, void_type_node, NULL, tbody, NULL); @@ -8182,7 +8321,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; case RESULT_DECL: - /* When within an OpenMP context, notice uses of variables. */ + /* When within an OMP context, notice uses of variables. */ if (gimplify_omp_ctxp) omp_notice_variable (gimplify_omp_ctxp, *expr_p, true); ret = GS_ALL_DONE; @@ -8208,9 +8347,38 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case CILK_SIMD: case CILK_FOR: case OMP_DISTRIBUTE: + case OACC_LOOP: ret = gimplify_omp_for (expr_p, pre_p); break; + case OACC_CACHE: + gimplify_oacc_cache (expr_p, pre_p); + ret = GS_ALL_DONE; + break; + + case OACC_HOST_DATA: + case OACC_DECLARE: + sorry ("directive not yet implemented"); + ret = GS_ALL_DONE; + break; + + case OACC_KERNELS: + if (OACC_KERNELS_COMBINED (*expr_p)) + sorry ("directive not yet implemented"); + else + gimplify_omp_workshare (expr_p, pre_p); + ret = GS_ALL_DONE; + break; + + case OACC_PARALLEL: + if (OACC_PARALLEL_COMBINED (*expr_p)) + sorry ("directive not yet implemented"); + else + gimplify_omp_workshare (expr_p, pre_p); + ret = GS_ALL_DONE; + break; + + case OACC_DATA: case OMP_SECTIONS: case OMP_SINGLE: case OMP_TARGET: @@ -8220,6 +8388,9 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ret = GS_ALL_DONE; break; + case OACC_ENTER_DATA: + case OACC_EXIT_DATA: + case OACC_UPDATE: case OMP_TARGET_UPDATE: gimplify_omp_target_update (expr_p, pre_p); ret = GS_ALL_DONE; @@ -8601,8 +8772,18 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && code != LOOP_EXPR && code != SWITCH_EXPR && code != TRY_FINALLY_EXPR + && code != OACC_PARALLEL + && code != OACC_KERNELS + && code != OACC_DATA + && code != OACC_HOST_DATA + && code != OACC_DECLARE + && code != OACC_UPDATE + && code != OACC_ENTER_DATA + && code != OACC_EXIT_DATA + && code != OACC_CACHE && code != OMP_CRITICAL && code != OMP_FOR + && code != OACC_LOOP && code != OMP_MASTER && code != OMP_TASKGROUP && code != OMP_ORDERED @@ -8829,7 +9010,7 @@ gimplify_body (tree fndecl, bool do_parms) gcc_assert (gimplify_ctxp == NULL); push_gimplify_context (); - if (flag_openmp) + if (flag_openacc || flag_openmp) { gcc_assert (gimplify_omp_ctxp == NULL); if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (fndecl))) @@ -8913,7 +9094,8 @@ gimplify_body (tree fndecl, bool do_parms) nonlocal_vlas = NULL; } - if ((flag_openmp || flag_openmp_simd) && gimplify_omp_ctxp) + if ((flag_openacc || flag_openmp || flag_openmp_simd) + && gimplify_omp_ctxp) { delete_omp_context (gimplify_omp_ctxp); gimplify_omp_ctxp = NULL; diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index bc265c2..cced43b9 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -82,6 +82,7 @@ along with GCC; see the file COPYING3. If not see #include "streamer-hooks.h" #include "cfgloop.h" #include "builtins.h" +#include "gomp-constants.h" static void lto_write_tree (struct output_block*, tree, bool); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 4eafacc..9b98edd 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,10 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + James Norris <jnorris@codesourcery.com> + + * lto-lang.c (DEF_FUNCTION_TYPE_VAR_8, DEF_FUNCTION_TYPE_VAR_12): + New macros. + * lto.c: Include "gomp-constants.h". + 2015-01-14 Ilya Verbin <ilya.verbin@intel.com> * lto-partition.c (lto_promote_cross_file_statics): Remove argument diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 31b0b5c..aa474e0 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -177,6 +177,11 @@ enum lto_builtin_type #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \ NAME, +#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) NAME, +#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, \ + ARG12) NAME, #define DEF_POINTER_TYPE(NAME, TYPE) NAME, #include "builtin-types.def" #undef DEF_PRIMITIVE_TYPE @@ -195,6 +200,8 @@ enum lto_builtin_type #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE BT_LAST }; @@ -679,6 +686,14 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8) \ + def_fn_type (ENUM, RETURN, 1, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8); +#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \ + def_fn_type (ENUM, RETURN, 1, 12, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \ + ARG7, ARG8, ARG9, ARG10, ARG11, ARG12); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); @@ -700,6 +715,8 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_FUNCTION_TYPE_VAR_8 +#undef DEF_FUNCTION_TYPE_VAR_12 #undef DEF_POINTER_TYPE builtin_types[(int) BT_LAST] = NULL_TREE; diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 96e5fd1..15d3f10 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -77,6 +77,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-inline.h" #include "params.h" #include "ipa-utils.h" +#include "gomp-constants.h" /* Number of parallel tasks to run, -1 if we want to use GNU Make jobserver. */ diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 47b6c6a..6aea7b7 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -1,5 +1,5 @@ /* This file contains the definitions and documentation for the - OpenMP builtins used in the GNU compiler. + Offloading and Multi Processing builtins used in the GNU compiler. Copyright (C) 2005-2015 Free Software Foundation, Inc. This file is part of GCC. @@ -20,10 +20,41 @@ along with GCC; see the file COPYING3. If not see /* Before including this file, you should define a macro: + DEF_GOACC_BUILTIN (ENUM, NAME, TYPE, ATTRS) + DEF_GOACC_BUILTIN_COMPILER (ENUM, NAME, TYPE, ATTRS) DEF_GOMP_BUILTIN (ENUM, NAME, TYPE, ATTRS) See builtins.def for details. */ +/* The reason why they aren't in gcc/builtins.def is that the Fortran front end + doesn't source those. */ + +DEF_GOACC_BUILTIN (BUILT_IN_ACC_GET_DEVICE_TYPE, "acc_get_device_type", + BT_FN_INT, ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DATA_START, "GOACC_data_start", + BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DATA_END, "GOACC_data_end", + BT_FN_VOID, ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_ENTER_EXIT_DATA, "GOACC_enter_exit_data", + BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR, + ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_PARALLEL, "GOACC_parallel", + BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR, + ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_UPDATE, "GOACC_update", + BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR, + ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_WAIT, "GOACC_wait", + BT_FN_VOID_INT_INT_VAR, + ATTR_NOTHROW_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_GET_THREAD_NUM, "GOACC_get_thread_num", + BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_GOACC_BUILTIN (BUILT_IN_GOACC_GET_NUM_THREADS, "GOACC_get_num_threads", + BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) + +DEF_GOACC_BUILTIN_COMPILER (BUILT_IN_ACC_ON_DEVICE, "acc_on_device", + BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST) + DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_THREAD_NUM, "omp_get_thread_num", BT_FN_INT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_OMP_GET_NUM_THREADS, "omp_get_num_threads", diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 9ec3d49..b7bf338 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1,6 +1,7 @@ -/* Lowering pass for OpenMP directives. Converts OpenMP directives - into explicit calls to the runtime library (libgomp) and data - marshalling to implement data sharing and copying clauses. +/* Lowering pass for OMP directives. Converts OMP directives into explicit + calls to the runtime library (libgomp), data marshalling to implement data + sharing and copying clauses, offloading to accelerators, and more. + Contributed by Diego Novillo <dnovillo@redhat.com> Copyright (C) 2005-2015 Free Software Foundation, Inc. @@ -106,9 +107,10 @@ along with GCC; see the file COPYING3. If not see #include "cilk.h" #include "context.h" #include "lto-section-names.h" +#include "gomp-constants.h" -/* Lowering of OpenMP parallel and workshare constructs proceeds in two +/* Lowering of OMP parallel and workshare constructs proceeds in two phases. The first phase scans the function looking for OMP statements and then for variables that must be replaced to satisfy data sharing clauses. The second phase expands code for the constructs, as well as @@ -116,10 +118,10 @@ along with GCC; see the file COPYING3. If not see expressions. Final code generation is done by pass_expand_omp. The flowgraph is - scanned for parallel regions which are then moved to a new - function, to be invoked by the thread library. */ + scanned for regions which are then moved to a new + function, to be invoked by the thread library, or offloaded. */ -/* Parallel region information. Every parallel and workshare +/* OMP region information. Every parallel and workshare directive is enclosed between two markers, the OMP_* directive and a corresponding OMP_RETURN statement. */ @@ -158,6 +160,12 @@ struct omp_region bool is_combined_parallel; }; +/* Levels of parallelism as defined by OpenACC. Increasing numbers + correspond to deeper loop nesting levels. */ +#define MASK_GANG 1 +#define MASK_WORKER 2 +#define MASK_VECTOR 4 + /* Context structure. Used to store information about each parallel directive in the code. */ @@ -192,6 +200,11 @@ typedef struct omp_context construct. In the case of a parallel, this is in the child function. */ tree block_vars; + /* A map of reduction pointer variables. For accelerators, each + reduction variable is replaced with an array. Each thread, in turn, + is assigned to a slot on that array. */ + splay_tree reduction_map; + /* Label to which GOMP_cancel{,llation_point} and explicit and implicit barriers should jump to during omplower pass. */ tree cancel_label; @@ -210,8 +223,18 @@ typedef struct omp_context /* True if this construct can be cancelled. */ bool cancellable; + + /* For OpenACC loops, a mask of gang, worker and vector used at + levels below this one. */ + int gwv_below; + /* For OpenACC loops, a mask of gang, worker and vector used at + this level and above. For parallel and kernels clauses, a mask + indicating which of num_gangs/num_workers/num_vectors was used. */ + int gwv_this; } omp_context; +/* A structure holding the elements of: + for (V = N1; V cond N2; V += STEP) [...] */ struct omp_for_data_loop { @@ -254,9 +277,93 @@ static tree scan_omp_1_op (tree *, int *, void *); *handled_ops_p = false; \ break; +/* Helper function to get the name of the array containing the partial + reductions for OpenACC reductions. */ +static const char * +oacc_get_reduction_array_id (tree node) +{ + const char *id = IDENTIFIER_POINTER (DECL_NAME (node)); + int len = strlen ("OACC") + strlen (id); + char *temp_name = XALLOCAVEC (char, len + 1); + snprintf (temp_name, len + 1, "OACC%s", id); + return IDENTIFIER_POINTER (get_identifier (temp_name)); +} + +/* Determine the number of threads OpenACC threads used to determine the + size of the array of partial reductions. Currently, this is num_gangs + * vector_length. This value may be different than GOACC_GET_NUM_THREADS, + because it is independed of the device used. */ + +static tree +oacc_max_threads (omp_context *ctx) +{ + tree nthreads, vector_length, gangs, clauses; + + gangs = fold_convert (sizetype, integer_one_node); + vector_length = gangs; + + /* The reduction clause may be nested inside a loop directive. + Scan for the innermost vector_length clause. */ + for (omp_context *oc = ctx; oc; oc = oc->outer) + { + if (gimple_code (oc->stmt) != GIMPLE_OMP_TARGET + || (gimple_omp_target_kind (oc->stmt) + != GF_OMP_TARGET_KIND_OACC_PARALLEL)) + continue; + + clauses = gimple_omp_target_clauses (oc->stmt); + + vector_length = find_omp_clause (clauses, OMP_CLAUSE_VECTOR_LENGTH); + if (vector_length) + vector_length = fold_convert_loc (OMP_CLAUSE_LOCATION (vector_length), + sizetype, + OMP_CLAUSE_VECTOR_LENGTH_EXPR + (vector_length)); + else + vector_length = fold_convert (sizetype, integer_one_node); + + gangs = find_omp_clause (clauses, OMP_CLAUSE_NUM_GANGS); + if (gangs) + gangs = fold_convert_loc (OMP_CLAUSE_LOCATION (gangs), sizetype, + OMP_CLAUSE_NUM_GANGS_EXPR (gangs)); + else + gangs = fold_convert (sizetype, integer_one_node); + + break; + } + + nthreads = fold_build2 (MULT_EXPR, sizetype, gangs, vector_length); + + return nthreads; +} + /* Holds offload tables with decls. */ vec<tree, va_gc> *offload_funcs, *offload_vars; +/* Holds a decl for __OFFLOAD_TABLE__. */ +static GTY(()) tree offload_symbol_decl; + +/* Get the __OFFLOAD_TABLE__ symbol. */ +static tree +get_offload_symbol_decl (void) +{ + if (!offload_symbol_decl) + { + tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, + get_identifier ("__OFFLOAD_TABLE__"), + ptr_type_node); + TREE_ADDRESSABLE (decl) = 1; + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = 1; + DECL_WEAK (decl) = 1; + DECL_ATTRIBUTES (decl) + = tree_cons (get_identifier ("weak"), + NULL_TREE, DECL_ATTRIBUTES (decl)); + offload_symbol_decl = decl; + } + return offload_symbol_decl; +} + /* Convenience function for calling scan_omp_1_op on tree operands. */ static inline tree @@ -275,7 +382,7 @@ static void lower_omp (gimple_seq *, omp_context *); static tree lookup_decl_in_outer_ctx (tree, omp_context *); static tree maybe_lookup_decl_in_outer_ctx (tree, omp_context *); -/* Find an OpenMP clause of type KIND within CLAUSES. */ +/* Find an OMP clause of type KIND within CLAUSES. */ tree find_omp_clause (tree clauses, enum omp_clause_code kind) @@ -296,16 +403,6 @@ is_parallel_ctx (omp_context *ctx) } -/* Return true if CTX is for an omp target region. */ - -static inline bool -is_targetreg_ctx (omp_context *ctx) -{ - return gimple_code (ctx->stmt) == GIMPLE_OMP_TARGET - && gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_REGION; -} - - /* Return true if CTX is for an omp task. */ static inline bool @@ -630,6 +727,15 @@ extract_omp_for_data (gomp_for *for_stmt, struct omp_for_data *fd, fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1); fd->loop.cond_code = LT_EXPR; } + + /* For OpenACC loops, force a chunk size of one, as this avoids the default + scheduling where several subsequent iterations are being executed by the + same thread. */ + if (gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP) + { + gcc_assert (fd->chunk_size == NULL_TREE); + fd->chunk_size = build_int_cst (TREE_TYPE (fd->loop.v), 1); + } } @@ -858,7 +964,18 @@ is_reference (tree decl) return lang_hooks.decls.omp_privatize_by_reference (decl); } -/* Lookup variables in the decl or field splay trees. The "maybe" form +/* Return the type of a decl. If the decl is reference type, + return its base type. */ +static inline tree +get_base_type (tree decl) +{ + tree type = TREE_TYPE (decl); + if (is_reference (decl)) + type = TREE_TYPE (type); + return type; +} + +/* Lookup variables. The "maybe" form allows for the variable form to not have been entered, otherwise we assert that the variable must have been entered. */ @@ -902,6 +1019,23 @@ maybe_lookup_field (tree var, omp_context *ctx) return n ? (tree) n->value : NULL_TREE; } +static inline tree +lookup_oacc_reduction (const char *id, omp_context *ctx) +{ + splay_tree_node n; + n = splay_tree_lookup (ctx->reduction_map, (splay_tree_key) id); + return (tree) n->value; +} + +static inline tree +maybe_lookup_oacc_reduction (tree var, omp_context *ctx) +{ + splay_tree_node n = NULL; + if (ctx->reduction_map) + n = splay_tree_lookup (ctx->reduction_map, (splay_tree_key) var); + return n ? (tree) n->value : NULL_TREE; +} + /* Return true if DECL should be copied by pointer. SHARED_CTX is the parallel context if DECL is to be shared. */ @@ -915,6 +1049,8 @@ use_pointer_for_field (tree decl, omp_context *shared_ctx) when we know the value is not accessible from an outer scope. */ if (shared_ctx) { + gcc_assert (!is_gimple_omp_oacc (shared_ctx->stmt)); + /* ??? Trivially accessible from anywhere. But why would we even be passing an address in this case? Should we simply assert this to be false, or should we have a cleanup pass that removes @@ -1119,6 +1255,8 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx) || !splay_tree_lookup (ctx->field_map, (splay_tree_key) var)); gcc_assert ((mask & 2) == 0 || !ctx->sfield_map || !splay_tree_lookup (ctx->sfield_map, (splay_tree_key) var)); + gcc_assert ((mask & 3) == 3 + || !is_gimple_omp_oacc (ctx->stmt)); type = TREE_TYPE (var); if (mask & 4) @@ -1395,6 +1533,7 @@ new_omp_context (gimple stmt, omp_context *outer_ctx) ctx->cb = outer_ctx->cb; ctx->cb.block = NULL; ctx->depth = outer_ctx->depth + 1; + ctx->reduction_map = outer_ctx->reduction_map; } else { @@ -1465,6 +1604,11 @@ delete_omp_context (splay_tree_value value) splay_tree_delete (ctx->field_map); if (ctx->sfield_map) splay_tree_delete (ctx->sfield_map); + if (ctx->reduction_map + /* Shared over several omp_contexts. */ + && (ctx->outer == NULL + || ctx->reduction_map != ctx->outer->reduction_map)) + splay_tree_delete (ctx->reduction_map); /* We hijacked DECL_ABSTRACT_ORIGIN earlier. We need to clear it before it produces corrupt debug information. */ @@ -1603,6 +1747,12 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) /* FALLTHRU */ case OMP_CLAUSE_FIRSTPRIVATE: + if (is_gimple_omp_oacc (ctx->stmt)) + { + sorry ("clause not supported yet"); + break; + } + /* FALLTHRU */ case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); @@ -1630,6 +1780,27 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) install_var_field (decl, by_ref, 3, ctx); } install_var_local (decl, ctx); + if (is_gimple_omp_oacc (ctx->stmt) + && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + /* Create a decl for the reduction array. */ + tree var = OMP_CLAUSE_DECL (c); + tree type = get_base_type (var); + tree ptype = build_pointer_type (type); + tree array = create_tmp_var (ptype, + oacc_get_reduction_array_id (var)); + omp_context *c = (ctx->field_map ? ctx : ctx->outer); + install_var_field (array, true, 3, c); + install_var_local (array, c); + + /* Insert it into the current context. */ + splay_tree_insert (ctx->reduction_map, (splay_tree_key) + oacc_get_reduction_array_id (var), + (splay_tree_value) array); + splay_tree_insert (ctx->reduction_map, + (splay_tree_key) array, + (splay_tree_value) array); + } break; case OMP_CLAUSE__LOOPTEMP_: @@ -1660,6 +1831,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_DIST_SCHEDULE: case OMP_CLAUSE_DEPEND: case OMP_CLAUSE__CILK_FOR_COUNT_: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: if (ctx->outer) scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer); break; @@ -1679,12 +1853,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) && varpool_node::get_create (decl)->offloadable) break; if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER) + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER) { - /* Ignore OMP_CLAUSE_MAP_POINTER kind for arrays in - #pragma omp target data, there is nothing to map for - those. */ - if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA + /* Ignore GOMP_MAP_POINTER kind for arrays in regions that are + not offloaded; there is nothing to map for those. */ + if (!is_gimple_omp_offloaded (ctx->stmt) && !POINTER_TYPE_P (TREE_TYPE (decl))) break; } @@ -1704,14 +1877,13 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) else { if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) install_var_field (decl, true, 7, ctx); else install_var_field (decl, true, 3, ctx); - if (gimple_omp_target_kind (ctx->stmt) - == GF_OMP_TARGET_KIND_REGION) + if (is_gimple_omp_offloaded (ctx->stmt)) install_var_local (decl, ctx); } } @@ -1723,7 +1895,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) && nc != NULL_TREE && OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP && OMP_CLAUSE_DECL (nc) == base - && OMP_CLAUSE_MAP_KIND (nc) == OMP_CLAUSE_MAP_POINTER + && OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_POINTER && integer_zerop (OMP_CLAUSE_SIZE (nc))) { OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) = 1; @@ -1756,6 +1928,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_MERGEABLE: case OMP_CLAUSE_PROC_BIND: case OMP_CLAUSE_SAFELEN: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_GANG: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: break; case OMP_CLAUSE_ALIGNED: @@ -1765,6 +1942,15 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) install_var_local (decl, ctx); break; + case OMP_CLAUSE_DEVICE_RESIDENT: + case OMP_CLAUSE_USE_DEVICE: + case OMP_CLAUSE__CACHE_: + case OMP_CLAUSE_INDEPENDENT: + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_SEQ: + sorry ("Clause not supported yet"); + break; + default: gcc_unreachable (); } @@ -1783,8 +1969,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) break; /* FALLTHRU */ - case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_FIRSTPRIVATE: + if (is_gimple_omp_oacc (ctx->stmt)) + { + sorry ("clause not supported yet"); + break; + } + /* FALLTHRU */ + case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); @@ -1811,7 +2003,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) break; case OMP_CLAUSE_MAP: - if (gimple_omp_target_kind (ctx->stmt) == GF_OMP_TARGET_KIND_DATA) + if (!is_gimple_omp_offloaded (ctx->stmt)) break; decl = OMP_CLAUSE_DECL (c); if (DECL_P (decl) @@ -1820,7 +2012,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) break; if (DECL_P (decl)) { - if (OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE && !COMPLETE_TYPE_P (TREE_TYPE (decl))) { @@ -1867,6 +2059,23 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: case OMP_CLAUSE__CILK_FOR_COUNT_: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: + case OMP_CLAUSE_GANG: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: + break; + + case OMP_CLAUSE_DEVICE_RESIDENT: + case OMP_CLAUSE_USE_DEVICE: + case OMP_CLAUSE__CACHE_: + case OMP_CLAUSE_INDEPENDENT: + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_SEQ: + sorry ("Clause not supported yet"); break; default: @@ -1874,6 +2083,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) } } + gcc_checking_assert (!scan_array_reductions + || !is_gimple_omp_oacc (ctx->stmt)); if (scan_array_reductions) for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION @@ -1956,6 +2167,8 @@ create_omp_child_function (omp_context *ctx, bool task_copy) decl = build_decl (gimple_location (ctx->stmt), FUNCTION_DECL, name, type); + gcc_checking_assert (!is_gimple_omp_oacc (ctx->stmt) + || !task_copy); if (!task_copy) ctx->cb.dst_fn = decl; else @@ -1976,7 +2189,7 @@ create_omp_child_function (omp_context *ctx, bool task_copy) { omp_context *octx; for (octx = ctx; octx; octx = octx->outer) - if (is_targetreg_ctx (octx)) + if (is_gimple_omp_offloaded (octx->stmt)) { cgraph_node::get_create (decl)->offloadable = 1; #ifdef ENABLE_OFFLOADING @@ -2311,17 +2524,84 @@ finish_taskreg_scan (omp_context *ctx) } -/* Scan an OpenMP loop directive. */ +static omp_context * +enclosing_target_ctx (omp_context *ctx) +{ + while (ctx != NULL + && gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET) + ctx = ctx->outer; + gcc_assert (ctx != NULL); + return ctx; +} + +static bool +oacc_loop_or_target_p (gimple stmt) +{ + enum gimple_code outer_type = gimple_code (stmt); + return ((outer_type == GIMPLE_OMP_TARGET + && ((gimple_omp_target_kind (stmt) + == GF_OMP_TARGET_KIND_OACC_PARALLEL) + || (gimple_omp_target_kind (stmt) + == GF_OMP_TARGET_KIND_OACC_KERNELS))) + || (outer_type == GIMPLE_OMP_FOR + && gimple_omp_for_kind (stmt) == GF_OMP_FOR_KIND_OACC_LOOP)); +} + +/* Scan a GIMPLE_OMP_FOR. */ static void scan_omp_for (gomp_for *stmt, omp_context *outer_ctx) { + enum gimple_code outer_type = GIMPLE_ERROR_MARK; omp_context *ctx; size_t i; + tree clauses = gimple_omp_for_clauses (stmt); + + if (outer_ctx) + outer_type = gimple_code (outer_ctx->stmt); ctx = new_omp_context (stmt, outer_ctx); - scan_sharing_clauses (gimple_omp_for_clauses (stmt), ctx); + if (is_gimple_omp_oacc (stmt)) + { + if (outer_ctx && outer_type == GIMPLE_OMP_FOR) + ctx->gwv_this = outer_ctx->gwv_this; + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + int val; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_GANG) + val = MASK_GANG; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_WORKER) + val = MASK_WORKER; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_VECTOR) + val = MASK_VECTOR; + else + continue; + ctx->gwv_this |= val; + if (!outer_ctx) + { + /* Skip; not nested inside a region. */ + continue; + } + if (!oacc_loop_or_target_p (outer_ctx->stmt)) + { + /* Skip; not nested inside an OpenACC region. */ + continue; + } + if (outer_type == GIMPLE_OMP_FOR) + outer_ctx->gwv_below |= val; + if (OMP_CLAUSE_OPERAND (c, 0) != NULL_TREE) + { + omp_context *enclosing = enclosing_target_ctx (outer_ctx); + if (gimple_omp_target_kind (enclosing->stmt) + == GF_OMP_TARGET_KIND_OACC_PARALLEL) + error_at (gimple_location (stmt), + "no arguments allowed to gang, worker and vector clauses inside parallel"); + } + } + } + + scan_sharing_clauses (clauses, ctx); scan_omp (gimple_omp_for_pre_body_ptr (stmt), ctx); for (i = 0; i < gimple_omp_for_collapse (stmt); i++) @@ -2332,6 +2612,19 @@ scan_omp_for (gomp_for *stmt, omp_context *outer_ctx) scan_omp_op (gimple_omp_for_incr_ptr (stmt, i), ctx); } scan_omp (gimple_omp_body_ptr (stmt), ctx); + + if (is_gimple_omp_oacc (stmt)) + { + if (ctx->gwv_this & ctx->gwv_below) + error_at (gimple_location (stmt), + "gang, worker and vector may occur only once in a loop nest"); + else if (ctx->gwv_below != 0 + && ctx->gwv_this > ctx->gwv_below) + error_at (gimple_location (stmt), + "gang, worker and vector must occur in this order in a loop nest"); + if (outer_ctx && outer_type == GIMPLE_OMP_FOR) + outer_ctx->gwv_below |= ctx->gwv_below; + } } /* Scan an OpenMP sections directive. */ @@ -2371,14 +2664,15 @@ scan_omp_single (gomp_single *stmt, omp_context *outer_ctx) layout_type (ctx->record_type); } -/* Scan an OpenMP target{, data, update} directive. */ +/* Scan a GIMPLE_OMP_TARGET. */ static void scan_omp_target (gomp_target *stmt, omp_context *outer_ctx) { omp_context *ctx; tree name; - int kind = gimple_omp_target_kind (stmt); + bool offloaded = is_gimple_omp_offloaded (stmt); + tree clauses = gimple_omp_target_clauses (stmt); ctx = new_omp_context (stmt, outer_ctx); ctx->field_map = splay_tree_new (splay_tree_compare_pointers, 0, 0); @@ -2390,13 +2684,30 @@ scan_omp_target (gomp_target *stmt, omp_context *outer_ctx) DECL_ARTIFICIAL (name) = 1; DECL_NAMELESS (name) = 1; TYPE_NAME (ctx->record_type) = name; - if (kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded) { + if (is_gimple_omp_oacc (stmt)) + ctx->reduction_map = splay_tree_new (splay_tree_compare_pointers, + 0, 0); + create_omp_child_function (ctx, false); gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn); } - scan_sharing_clauses (gimple_omp_target_clauses (stmt), ctx); + if (is_gimple_omp_oacc (stmt)) + { + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_GANGS) + ctx->gwv_this |= MASK_GANG; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_WORKERS) + ctx->gwv_this |= MASK_WORKER; + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_VECTOR_LENGTH) + ctx->gwv_this |= MASK_VECTOR; + } + } + + scan_sharing_clauses (clauses, ctx); scan_omp (gimple_omp_body_ptr (stmt), ctx); if (TYPE_FIELDS (ctx->record_type) == NULL) @@ -2414,7 +2725,7 @@ scan_omp_target (gomp_target *stmt, omp_context *outer_ctx) gcc_assert (DECL_ALIGN (field) == align); #endif layout_type (ctx->record_type); - if (kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded) fixup_child_record_type (ctx); } } @@ -2429,10 +2740,25 @@ scan_omp_teams (gomp_teams *stmt, omp_context *outer_ctx) scan_omp (gimple_omp_body_ptr (stmt), ctx); } -/* Check OpenMP nesting restrictions. */ +/* Check nesting restrictions. */ static bool check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) { + /* No nesting of non-OpenACC STMT (that is, an OpenMP one, or a GOMP builtin) + inside an OpenACC CTX. */ + if (!(is_gimple_omp (stmt) + && is_gimple_omp_oacc (stmt))) + { + for (omp_context *ctx_ = ctx; ctx_ != NULL; ctx_ = ctx_->outer) + if (is_gimple_omp (ctx_->stmt) + && is_gimple_omp_oacc (ctx_->stmt)) + { + error_at (gimple_location (stmt), + "non-OpenACC construct inside of OpenACC region"); + return false; + } + } + if (ctx != NULL) { if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR @@ -2693,19 +3019,74 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) break; case GIMPLE_OMP_TARGET: for (; ctx != NULL; ctx = ctx->outer) - if (is_targetreg_ctx (ctx)) - { - const char *name; - switch (gimple_omp_target_kind (stmt)) - { - case GF_OMP_TARGET_KIND_REGION: name = "target"; break; - case GF_OMP_TARGET_KIND_DATA: name = "target data"; break; - case GF_OMP_TARGET_KIND_UPDATE: name = "target update"; break; - default: gcc_unreachable (); - } - warning_at (gimple_location (stmt), 0, - "%s construct inside of target region", name); - } + { + if (gimple_code (ctx->stmt) != GIMPLE_OMP_TARGET) + { + if (is_gimple_omp (stmt) + && is_gimple_omp_oacc (stmt) + && is_gimple_omp (ctx->stmt)) + { + error_at (gimple_location (stmt), + "OpenACC construct inside of non-OpenACC region"); + return false; + } + continue; + } + + const char *stmt_name, *ctx_stmt_name; + switch (gimple_omp_target_kind (stmt)) + { + case GF_OMP_TARGET_KIND_REGION: stmt_name = "target"; break; + case GF_OMP_TARGET_KIND_DATA: stmt_name = "target data"; break; + case GF_OMP_TARGET_KIND_UPDATE: stmt_name = "target update"; break; + case GF_OMP_TARGET_KIND_OACC_PARALLEL: stmt_name = "parallel"; break; + case GF_OMP_TARGET_KIND_OACC_KERNELS: stmt_name = "kernels"; break; + case GF_OMP_TARGET_KIND_OACC_DATA: stmt_name = "data"; break; + case GF_OMP_TARGET_KIND_OACC_UPDATE: stmt_name = "update"; break; + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: stmt_name = "enter/exit data"; break; + default: gcc_unreachable (); + } + switch (gimple_omp_target_kind (ctx->stmt)) + { + case GF_OMP_TARGET_KIND_REGION: ctx_stmt_name = "target"; break; + case GF_OMP_TARGET_KIND_DATA: ctx_stmt_name = "target data"; break; + case GF_OMP_TARGET_KIND_OACC_PARALLEL: ctx_stmt_name = "parallel"; break; + case GF_OMP_TARGET_KIND_OACC_KERNELS: ctx_stmt_name = "kernels"; break; + case GF_OMP_TARGET_KIND_OACC_DATA: ctx_stmt_name = "data"; break; + default: gcc_unreachable (); + } + + /* OpenACC/OpenMP mismatch? */ + if (is_gimple_omp_oacc (stmt) + != is_gimple_omp_oacc (ctx->stmt)) + { + error_at (gimple_location (stmt), + "%s %s construct inside of %s %s region", + (is_gimple_omp_oacc (stmt) + ? "OpenACC" : "OpenMP"), stmt_name, + (is_gimple_omp_oacc (ctx->stmt) + ? "OpenACC" : "OpenMP"), ctx_stmt_name); + return false; + } + if (is_gimple_omp_offloaded (ctx->stmt)) + { + /* No GIMPLE_OMP_TARGET inside offloaded OpenACC CTX. */ + if (is_gimple_omp_oacc (ctx->stmt)) + { + error_at (gimple_location (stmt), + "%s construct inside of %s region", + stmt_name, ctx_stmt_name); + return false; + } + else + { + gcc_checking_assert (!is_gimple_omp_oacc (stmt)); + warning_at (gimple_location (stmt), 0, + "%s construct inside of %s region", + stmt_name, ctx_stmt_name); + } + } + } break; default: break; @@ -2717,7 +3098,7 @@ check_omp_nesting_restrictions (gimple stmt, omp_context *ctx) /* Helper function scan_omp. Callback for walk_tree or operators in walk_gimple_stmt used to - scan for OpenMP directives in TP. */ + scan for OMP directives in TP. */ static tree scan_omp_1_op (tree *tp, int *walk_subtrees, void *data) @@ -2780,7 +3161,7 @@ setjmp_or_longjmp_p (const_tree fndecl) /* Helper function for scan_omp. - Callback for walk_gimple_stmt used to scan for OpenMP directives in + Callback for walk_gimple_stmt used to scan for OMP directives in the current statement in GSI. */ static tree @@ -2793,7 +3174,7 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, if (gimple_has_location (stmt)) input_location = gimple_location (stmt); - /* Check the OpenMP nesting restrictions. */ + /* Check the nesting restrictions. */ bool remove = false; if (is_gimple_omp (stmt)) remove = !check_omp_nesting_restrictions (stmt, ctx); @@ -2901,7 +3282,7 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, /* Scan all the statements starting at the current statement. CTX - contains context information about the OpenMP directives and + contains context information about the OMP directives and clauses found during the scan. */ static void @@ -4086,6 +4467,57 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list, gimple_seq_add_stmt (stmt_list, gimple_build_label (label)); } +static void +oacc_lower_reduction_var_helper (gimple_seq *stmt_seqp, omp_context *ctx, + tree tid, tree var, tree new_var) +{ + /* The atomic add at the end of the sum creates unnecessary + write contention on accelerators. To work around this, + create an array to store the partial reductions. Later, in + lower_omp_for (for openacc), the values of array will be + combined. */ + + tree t = NULL_TREE, array, x; + tree type = get_base_type (var); + gimple stmt; + + /* Now insert the partial reductions into the array. */ + + /* Find the reduction array. */ + + tree ptype = build_pointer_type (type); + + t = lookup_oacc_reduction (oacc_get_reduction_array_id (var), ctx); + t = build_receiver_ref (t, false, ctx->outer); + + array = create_tmp_var (ptype); + gimplify_assign (array, t, stmt_seqp); + + tree ptr = create_tmp_var (TREE_TYPE (array)); + + /* Find the reduction array. */ + + /* testing a unary conversion. */ + tree offset = create_tmp_var (sizetype); + gimplify_assign (offset, TYPE_SIZE_UNIT (type), + stmt_seqp); + t = create_tmp_var (sizetype); + gimplify_assign (t, unshare_expr (fold_build1 (NOP_EXPR, sizetype, tid)), + stmt_seqp); + stmt = gimple_build_assign (offset, MULT_EXPR, offset, t); + gimple_seq_add_stmt (stmt_seqp, stmt); + + /* Offset expression. Does the POINTER_PLUS_EXPR take care + of adding sizeof(var) to the array? */ + ptr = create_tmp_var (ptype); + stmt = gimple_build_assign (unshare_expr (ptr), POINTER_PLUS_EXPR, array, + offset); + gimple_seq_add_stmt (stmt_seqp, stmt); + + /* Move the local sum to gfc$sum[i]. */ + x = unshare_expr (build_simple_mem_ref (ptr)); + stmt = gimplify_assign (x, new_var, stmt_seqp); +} /* Generate code to implement the REDUCTION clauses. */ @@ -4094,7 +4526,7 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) { gimple_seq sub_seq = NULL; gimple stmt; - tree x, c; + tree x, c, tid = NULL_TREE; int count = 0; /* SIMD reductions are handled in lower_rec_input_clauses. */ @@ -4119,6 +4551,17 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) if (count == 0) return; + /* Initialize thread info for OpenACC. */ + if (is_gimple_omp_oacc (ctx->stmt)) + { + /* Get the current thread id. */ + tree call = builtin_decl_explicit (BUILT_IN_GOACC_GET_THREAD_NUM); + tid = create_tmp_var (TREE_TYPE (TREE_TYPE (call))); + gimple stmt = gimple_build_call (call, 0); + gimple_call_set_lhs (stmt, tid); + gimple_seq_add_stmt (stmt_seqp, stmt); + } + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) { tree var, ref, new_var; @@ -4140,7 +4583,13 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) if (code == MINUS_EXPR) code = PLUS_EXPR; - if (count == 1) + if (is_gimple_omp_oacc (ctx->stmt)) + { + gcc_checking_assert (!OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)); + + oacc_lower_reduction_var_helper (stmt_seqp, ctx, tid, var, new_var); + } + else if (count == 1) { tree addr = build_fold_addr_expr_loc (clause_loc, ref); @@ -4151,8 +4600,7 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) gimplify_and_add (x, stmt_seqp); return; } - - if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) + else if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) { tree placeholder = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c); @@ -4175,6 +4623,9 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx) } } + if (is_gimple_omp_oacc (ctx->stmt)) + return; + stmt = gimple_build_call (builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START), 0); gimple_seq_add_stmt (stmt_seqp, stmt); @@ -6065,12 +6516,14 @@ expand_omp_for_static_nochunk (struct omp_region *region, basic_block fin_bb; gimple_stmt_iterator gsi; edge ep; - enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; - enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; bool broken_loop = region->cont == NULL; tree *counts = NULL; tree n1, n2, step; + gcc_checking_assert ((gimple_omp_for_kind (fd->for_stmt) + != GF_OMP_FOR_KIND_OACC_LOOP) + || !inner_stmt); + itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) itype = signed_type_for (type); @@ -6094,12 +6547,6 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); - if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) - { - get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS; - get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; - } - if (fd->collapse > 1) { int first_zero_iter = -1; @@ -6158,14 +6605,30 @@ expand_omp_for_static_nochunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); } - t = build_call_expr (builtin_decl_explicit (get_num_threads), 0); - t = fold_convert (itype, t); - nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + switch (gimple_omp_for_kind (fd->for_stmt)) + { + case GF_OMP_FOR_KIND_FOR: + nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS); + threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM); + break; + case GF_OMP_FOR_KIND_DISTRIBUTE: + nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_TEAMS); + threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_TEAM_NUM); + break; + case GF_OMP_FOR_KIND_OACC_LOOP: + nthreads = builtin_decl_explicit (BUILT_IN_GOACC_GET_NUM_THREADS); + threadid = builtin_decl_explicit (BUILT_IN_GOACC_GET_THREAD_NUM); + break; + default: + gcc_unreachable (); + } + nthreads = build_call_expr (nthreads, 0); + nthreads = fold_convert (itype, nthreads); + nthreads = force_gimple_operand_gsi (&gsi, nthreads, true, NULL_TREE, true, GSI_SAME_STMT); - - t = build_call_expr (builtin_decl_explicit (get_thread_num), 0); - t = fold_convert (itype, t); - threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + threadid = build_call_expr (threadid, 0); + threadid = fold_convert (itype, threadid); + threadid = force_gimple_operand_gsi (&gsi, threadid, true, NULL_TREE, true, GSI_SAME_STMT); n1 = fd->loop.n1; @@ -6339,7 +6802,10 @@ expand_omp_for_static_nochunk (struct omp_region *region, if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) { t = gimple_omp_return_lhs (gsi_stmt (gsi)); - gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT); + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP) + gcc_checking_assert (t == NULL_TREE); + else + gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT); } gsi_remove (&gsi, true); @@ -6440,12 +6906,14 @@ expand_omp_for_static_chunk (struct omp_region *region, basic_block trip_update_bb = NULL, cont_bb, collapse_bb = NULL, fin_bb; gimple_stmt_iterator gsi; edge se; - enum built_in_function get_num_threads = BUILT_IN_OMP_GET_NUM_THREADS; - enum built_in_function get_thread_num = BUILT_IN_OMP_GET_THREAD_NUM; bool broken_loop = region->cont == NULL; tree *counts = NULL; tree n1, n2, step; + gcc_checking_assert ((gimple_omp_for_kind (fd->for_stmt) + != GF_OMP_FOR_KIND_OACC_LOOP) + || !inner_stmt); + itype = type = TREE_TYPE (fd->loop.v); if (POINTER_TYPE_P (type)) itype = signed_type_for (type); @@ -6473,12 +6941,6 @@ expand_omp_for_static_chunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_FOR); - if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_DISTRIBUTE) - { - get_num_threads = BUILT_IN_OMP_GET_NUM_TEAMS; - get_thread_num = BUILT_IN_OMP_GET_TEAM_NUM; - } - if (fd->collapse > 1) { int first_zero_iter = -1; @@ -6537,14 +6999,30 @@ expand_omp_for_static_chunk (struct omp_region *region, gsi = gsi_last_bb (entry_bb); } - t = build_call_expr (builtin_decl_explicit (get_num_threads), 0); - t = fold_convert (itype, t); - nthreads = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + switch (gimple_omp_for_kind (fd->for_stmt)) + { + case GF_OMP_FOR_KIND_FOR: + nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_THREADS); + threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM); + break; + case GF_OMP_FOR_KIND_DISTRIBUTE: + nthreads = builtin_decl_explicit (BUILT_IN_OMP_GET_NUM_TEAMS); + threadid = builtin_decl_explicit (BUILT_IN_OMP_GET_TEAM_NUM); + break; + case GF_OMP_FOR_KIND_OACC_LOOP: + nthreads = builtin_decl_explicit (BUILT_IN_GOACC_GET_NUM_THREADS); + threadid = builtin_decl_explicit (BUILT_IN_GOACC_GET_THREAD_NUM); + break; + default: + gcc_unreachable (); + } + nthreads = build_call_expr (nthreads, 0); + nthreads = fold_convert (itype, nthreads); + nthreads = force_gimple_operand_gsi (&gsi, nthreads, true, NULL_TREE, true, GSI_SAME_STMT); - - t = build_call_expr (builtin_decl_explicit (get_thread_num), 0); - t = fold_convert (itype, t); - threadid = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, + threadid = build_call_expr (threadid, 0); + threadid = fold_convert (itype, threadid); + threadid = force_gimple_operand_gsi (&gsi, threadid, true, NULL_TREE, true, GSI_SAME_STMT); n1 = fd->loop.n1; @@ -6735,7 +7213,10 @@ expand_omp_for_static_chunk (struct omp_region *region, if (!gimple_omp_return_nowait_p (gsi_stmt (gsi))) { t = gimple_omp_return_lhs (gsi_stmt (gsi)); - gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT); + if (gimple_omp_for_kind (fd->for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP) + gcc_checking_assert (t == NULL_TREE); + else + gsi_insert_after (&gsi, build_omp_barrier (t), GSI_SAME_STMT); } gsi_remove (&gsi, true); @@ -7350,7 +7831,7 @@ expand_omp_simd (struct omp_region *region, struct omp_for_data *fd) } -/* Expand the OpenMP loop defined by REGION. */ +/* Expand the OMP loop defined by REGION. */ static void expand_omp_for (struct omp_region *region, gimple inner_stmt) @@ -8290,56 +8771,83 @@ expand_omp_atomic (struct omp_region *region) } -/* Expand the OpenMP target{, data, update} directive starting at REGION. */ +/* Expand the GIMPLE_OMP_TARGET starting at REGION. */ static void expand_omp_target (struct omp_region *region) { basic_block entry_bb, exit_bb, new_bb; - struct function *child_cfun = NULL; - tree child_fn = NULL_TREE, block, t; + struct function *child_cfun; + tree child_fn, block, t; gimple_stmt_iterator gsi; gomp_target *entry_stmt; gimple stmt; edge e; + bool offloaded, data_region; entry_stmt = as_a <gomp_target *> (last_stmt (region->entry)); new_bb = region->entry; - int kind = gimple_omp_target_kind (entry_stmt); - if (kind == GF_OMP_TARGET_KIND_REGION) + + offloaded = is_gimple_omp_offloaded (entry_stmt); + switch (gimple_omp_target_kind (entry_stmt)) + { + case GF_OMP_TARGET_KIND_REGION: + case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: + case GF_OMP_TARGET_KIND_OACC_UPDATE: + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + data_region = false; + break; + case GF_OMP_TARGET_KIND_DATA: + case GF_OMP_TARGET_KIND_OACC_DATA: + data_region = true; + break; + default: + gcc_unreachable (); + } + + child_fn = NULL_TREE; + child_cfun = NULL; + if (offloaded) { child_fn = gimple_omp_target_child_fn (entry_stmt); child_cfun = DECL_STRUCT_FUNCTION (child_fn); } + /* Supported by expand_omp_taskreg, but not here. */ + if (child_cfun != NULL) + gcc_checking_assert (!child_cfun->cfg); + gcc_checking_assert (!gimple_in_ssa_p (cfun)); + entry_bb = region->entry; exit_bb = region->exit; - if (kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded) { unsigned srcidx, dstidx, num; - /* If the target region needs data sent from the parent + /* If the offloading region needs data sent from the parent function, then the very first statement (except possible - tree profile counter updates) of the parallel body + tree profile counter updates) of the offloading body is a copy assignment .OMP_DATA_I = &.OMP_DATA_O. Since &.OMP_DATA_O is passed as an argument to the child function, we need to replace it with the argument as seen by the child function. In most cases, this will end up being the identity assignment - .OMP_DATA_I = .OMP_DATA_I. However, if the parallel body had + .OMP_DATA_I = .OMP_DATA_I. However, if the offloading body had a function call that has been inlined, the original PARM_DECL .OMP_DATA_I may have been converted into a different local variable. In which case, we need to keep the assignment. */ - if (gimple_omp_target_data_arg (entry_stmt)) + tree data_arg = gimple_omp_target_data_arg (entry_stmt); + if (data_arg) { basic_block entry_succ_bb = single_succ (entry_bb); gimple_stmt_iterator gsi; tree arg; gimple tgtcopy_stmt = NULL; - tree sender - = TREE_VEC_ELT (gimple_omp_target_data_arg (entry_stmt), 0); + tree sender = TREE_VEC_ELT (data_arg, 0); for (gsi = gsi_start_bb (entry_succ_bb); ; gsi_next (&gsi)) { @@ -8374,7 +8882,7 @@ expand_omp_target (struct omp_region *region) /* Declare local variables needed in CHILD_CFUN. */ block = DECL_INITIAL (child_fn); BLOCK_VARS (block) = vec2chain (child_cfun->local_decls); - /* The gimplifier could record temporaries in target block + /* The gimplifier could record temporaries in the offloading block rather than in containing function's local_decls chain, which would mean cgraph missed finalizing them. Do it now. */ for (t = BLOCK_VARS (block); t; t = DECL_CHAIN (t)) @@ -8391,13 +8899,12 @@ expand_omp_target (struct omp_region *region) for (t = DECL_ARGUMENTS (child_fn); t; t = DECL_CHAIN (t)) DECL_CONTEXT (t) = child_fn; - /* Split ENTRY_BB at GIMPLE_OMP_TARGET, + /* Split ENTRY_BB at GIMPLE_*, so that it can be moved to the child function. */ gsi = gsi_last_bb (entry_bb); stmt = gsi_stmt (gsi); - gcc_assert (stmt && gimple_code (stmt) == GIMPLE_OMP_TARGET - && gimple_omp_target_kind (stmt) - == GF_OMP_TARGET_KIND_REGION); + gcc_assert (stmt + && gimple_code (stmt) == gimple_code (entry_stmt)); gsi_remove (&gsi, true); e = split_block (entry_bb, stmt); entry_bb = e->dest; @@ -8414,7 +8921,7 @@ expand_omp_target (struct omp_region *region) gsi_remove (&gsi, true); } - /* Move the target region into CHILD_CFUN. */ + /* Move the offloading region into CHILD_CFUN. */ block = gimple_block (entry_stmt); @@ -8478,25 +8985,46 @@ expand_omp_target (struct omp_region *region) pop_cfun (); } - /* Emit a library call to launch the target region, or do data + /* Emit a library call to launch the offloading region, or do data transfers. */ tree t1, t2, t3, t4, device, cond, c, clauses; enum built_in_function start_ix; location_t clause_loc; - clauses = gimple_omp_target_clauses (entry_stmt); + switch (gimple_omp_target_kind (entry_stmt)) + { + case GF_OMP_TARGET_KIND_REGION: + start_ix = BUILT_IN_GOMP_TARGET; + break; + case GF_OMP_TARGET_KIND_DATA: + start_ix = BUILT_IN_GOMP_TARGET_DATA; + break; + case GF_OMP_TARGET_KIND_UPDATE: + start_ix = BUILT_IN_GOMP_TARGET_UPDATE; + break; + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: + start_ix = BUILT_IN_GOACC_PARALLEL; + break; + case GF_OMP_TARGET_KIND_OACC_DATA: + start_ix = BUILT_IN_GOACC_DATA_START; + break; + case GF_OMP_TARGET_KIND_OACC_UPDATE: + start_ix = BUILT_IN_GOACC_UPDATE; + break; + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + start_ix = BUILT_IN_GOACC_ENTER_EXIT_DATA; + break; + default: + gcc_unreachable (); + } - if (kind == GF_OMP_TARGET_KIND_REGION) - start_ix = BUILT_IN_GOMP_TARGET; - else if (kind == GF_OMP_TARGET_KIND_DATA) - start_ix = BUILT_IN_GOMP_TARGET_DATA; - else - start_ix = BUILT_IN_GOMP_TARGET_UPDATE; + clauses = gimple_omp_target_clauses (entry_stmt); - /* By default, the value of DEVICE is -1 (let runtime library choose) - and there is no conditional. */ + /* By default, the value of DEVICE is GOMP_DEVICE_ICV (let runtime + library choose) and there is no conditional. */ cond = NULL_TREE; - device = build_int_cst (integer_type_node, -1); + device = build_int_cst (integer_type_node, GOMP_DEVICE_ICV); c = find_omp_clause (clauses, OMP_CLAUSE_IF); if (c) @@ -8505,6 +9033,12 @@ expand_omp_target (struct omp_region *region) c = find_omp_clause (clauses, OMP_CLAUSE_DEVICE); if (c) { + /* Even if we pass it to all library function calls, it is currently only + defined/used for the OpenMP target ones. */ + gcc_checking_assert (start_ix == BUILT_IN_GOMP_TARGET + || start_ix == BUILT_IN_GOMP_TARGET_DATA + || start_ix == BUILT_IN_GOMP_TARGET_UPDATE); + device = OMP_CLAUSE_DEVICE_ID (c); clause_loc = OMP_CLAUSE_LOCATION (c); } @@ -8515,7 +9049,7 @@ expand_omp_target (struct omp_region *region) device = fold_convert_loc (clause_loc, integer_type_node, device); /* If we found the clause 'if (cond)', build - (cond ? device : -2). */ + (cond ? device : GOMP_DEVICE_HOST_FALLBACK). */ if (cond) { cond = gimple_boolify (cond); @@ -8525,14 +9059,14 @@ expand_omp_target (struct omp_region *region) tree tmp_var; tmp_var = create_tmp_var (TREE_TYPE (device)); - if (kind != GF_OMP_TARGET_KIND_REGION) + if (offloaded) + e = split_block (new_bb, NULL); + else { gsi = gsi_last_bb (new_bb); gsi_prev (&gsi); e = split_block (new_bb, gsi_stmt (gsi)); } - else - e = split_block (new_bb, NULL); cond_bb = e->src; new_bb = e->dest; remove_edge (e); @@ -8552,7 +9086,8 @@ expand_omp_target (struct omp_region *region) gsi = gsi_start_bb (else_bb); stmt = gimple_build_assign (tmp_var, - build_int_cst (integer_type_node, -2)); + build_int_cst (integer_type_node, + GOMP_DEVICE_HOST_FALLBACK)); gsi_insert_after (&gsi, stmt, GSI_CONTINUE_LINKING); make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE); @@ -8584,28 +9119,124 @@ expand_omp_target (struct omp_region *region) } gimple g; - /* FIXME: This will be address of - extern char __OPENMP_TARGET__[] __attribute__((visibility ("hidden"))) - symbol, as soon as the linker plugin is able to create it for us. */ - tree openmp_target = build_zero_cst (ptr_type_node); - if (kind == GF_OMP_TARGET_KIND_REGION) - { - tree fnaddr = build_fold_addr_expr (child_fn); - g = gimple_build_call (builtin_decl_explicit (start_ix), 7, - device, fnaddr, openmp_target, t1, t2, t3, t4); + tree offload_table = get_offload_symbol_decl (); + vec<tree> *args; + /* The maximum number used by any start_ix, without varargs. */ + unsigned int argcnt = 12; + + vec_alloc (args, argcnt); + args->quick_push (device); + if (offloaded) + args->quick_push (build_fold_addr_expr (child_fn)); + args->quick_push (build_fold_addr_expr (offload_table)); + args->quick_push (t1); + args->quick_push (t2); + args->quick_push (t3); + args->quick_push (t4); + switch (start_ix) + { + case BUILT_IN_GOACC_DATA_START: + case BUILT_IN_GOMP_TARGET: + case BUILT_IN_GOMP_TARGET_DATA: + case BUILT_IN_GOMP_TARGET_UPDATE: + break; + case BUILT_IN_GOACC_PARALLEL: + { + tree t_num_gangs, t_num_workers, t_vector_length; + + /* Default values for num_gangs, num_workers, and vector_length. */ + t_num_gangs = t_num_workers = t_vector_length + = fold_convert_loc (gimple_location (entry_stmt), + integer_type_node, integer_one_node); + /* ..., but if present, use the value specified by the respective + clause, making sure that are of the correct type. */ + c = find_omp_clause (clauses, OMP_CLAUSE_NUM_GANGS); + if (c) + t_num_gangs = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + integer_type_node, + OMP_CLAUSE_NUM_GANGS_EXPR (c)); + c = find_omp_clause (clauses, OMP_CLAUSE_NUM_WORKERS); + if (c) + t_num_workers = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + integer_type_node, + OMP_CLAUSE_NUM_WORKERS_EXPR (c)); + c = find_omp_clause (clauses, OMP_CLAUSE_VECTOR_LENGTH); + if (c) + t_vector_length = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + integer_type_node, + OMP_CLAUSE_VECTOR_LENGTH_EXPR (c)); + args->quick_push (t_num_gangs); + args->quick_push (t_num_workers); + args->quick_push (t_vector_length); + } + /* FALLTHRU */ + case BUILT_IN_GOACC_ENTER_EXIT_DATA: + case BUILT_IN_GOACC_UPDATE: + { + tree t_async; + int t_wait_idx; + + /* Default values for t_async. */ + t_async = fold_convert_loc (gimple_location (entry_stmt), + integer_type_node, + build_int_cst (integer_type_node, + GOMP_ASYNC_SYNC)); + /* ..., but if present, use the value specified by the respective + clause, making sure that is of the correct type. */ + c = find_omp_clause (clauses, OMP_CLAUSE_ASYNC); + if (c) + t_async = fold_convert_loc (OMP_CLAUSE_LOCATION (c), + integer_type_node, + OMP_CLAUSE_ASYNC_EXPR (c)); + + args->quick_push (t_async); + /* Save the index, and... */ + t_wait_idx = args->length (); + /* ... push a default value. */ + args->quick_push (fold_convert_loc (gimple_location (entry_stmt), + integer_type_node, + integer_zero_node)); + c = find_omp_clause (clauses, OMP_CLAUSE_WAIT); + if (c) + { + int n = 0; + + for (; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_WAIT) + { + args->safe_push (fold_convert_loc (OMP_CLAUSE_LOCATION (c), + integer_type_node, + OMP_CLAUSE_WAIT_EXPR (c))); + n++; + } + } + + /* Now that we know the number, replace the default value. */ + args->ordered_remove (t_wait_idx); + args->quick_insert (t_wait_idx, + fold_convert_loc (gimple_location (entry_stmt), + integer_type_node, + build_int_cst (integer_type_node, n))); + } + } + break; + default: + gcc_unreachable (); } - else - g = gimple_build_call (builtin_decl_explicit (start_ix), 6, - device, openmp_target, t1, t2, t3, t4); + + g = gimple_build_call_vec (builtin_decl_explicit (start_ix), *args); + args->release (); gimple_set_location (g, gimple_location (entry_stmt)); gsi_insert_before (&gsi, g, GSI_SAME_STMT); - if (kind != GF_OMP_TARGET_KIND_REGION) + if (!offloaded) { g = gsi_stmt (gsi); gcc_assert (g && gimple_code (g) == GIMPLE_OMP_TARGET); gsi_remove (&gsi, true); } - if (kind == GF_OMP_TARGET_KIND_DATA && region->exit) + if (data_region + && region->exit) { gsi = gsi_last_bb (region->exit); g = gsi_stmt (gsi); @@ -8737,7 +9368,6 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent, region->exit = bb; parent = parent->outer; } - else if (code == GIMPLE_OMP_CONTINUE) { gcc_assert (parent); @@ -8747,17 +9377,34 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent, { /* GIMPLE_OMP_SECTIONS_SWITCH is part of GIMPLE_OMP_SECTIONS, and we do nothing for it. */ - ; } - else if (code == GIMPLE_OMP_TARGET - && gimple_omp_target_kind (stmt) == GF_OMP_TARGET_KIND_UPDATE) - new_omp_region (bb, code, parent); else { - /* Otherwise, this directive becomes the parent for a new - region. */ region = new_omp_region (bb, code, parent); - parent = region; + /* Otherwise... */ + if (code == GIMPLE_OMP_TARGET) + { + switch (gimple_omp_target_kind (stmt)) + { + case GF_OMP_TARGET_KIND_REGION: + case GF_OMP_TARGET_KIND_DATA: + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: + case GF_OMP_TARGET_KIND_OACC_DATA: + break; + case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_OACC_UPDATE: + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + /* ..., other than for those stand-alone directives... */ + region = NULL; + break; + default: + gcc_unreachable (); + } + } + /* ..., this directive becomes the parent for a new region. */ + if (region) + parent = region; } } @@ -8866,11 +9513,12 @@ public: /* opt_pass methods: */ virtual unsigned int execute (function *) { - bool gate = ((flag_openmp != 0 || flag_openmp_simd != 0 - || flag_cilkplus != 0) && !seen_error ()); + bool gate = ((flag_cilkplus != 0 || flag_openacc != 0 || flag_openmp != 0 + || flag_openmp_simd != 0) + && !seen_error ()); /* This pass always runs, to provide PROP_gimple_eomp. - But there is nothing to do unless -fopenmp is given. */ + But often, there is nothing to do. */ if (!gate) return 0; @@ -8926,7 +9574,394 @@ make_pass_expand_omp_ssa (gcc::context *ctxt) return new pass_expand_omp_ssa (ctxt); } -/* Routines to lower OpenMP directives into OMP-GIMPLE. */ +/* Routines to lower OMP directives into OMP-GIMPLE. */ + +/* Helper function to preform, potentially COMPLEX_TYPE, operation and + convert it to gimple. */ +static void +oacc_gimple_assign (tree dest, tree_code op, tree src, gimple_seq *seq) +{ + gimple stmt; + + if (TREE_CODE (TREE_TYPE (dest)) != COMPLEX_TYPE) + { + stmt = gimple_build_assign (dest, op, dest, src); + gimple_seq_add_stmt (seq, stmt); + return; + } + + tree t = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + tree rdest = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (dest)), dest); + gimplify_assign (t, rdest, seq); + rdest = t; + + t = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + tree idest = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (dest)), dest); + gimplify_assign (t, idest, seq); + idest = t; + + t = create_tmp_var (TREE_TYPE (TREE_TYPE (src))); + tree rsrc = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (src)), src); + gimplify_assign (t, rsrc, seq); + rsrc = t; + + t = create_tmp_var (TREE_TYPE (TREE_TYPE (src))); + tree isrc = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (src)), src); + gimplify_assign (t, isrc, seq); + isrc = t; + + tree r = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + tree i = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + tree result; + + if (op == PLUS_EXPR) + { + stmt = gimple_build_assign (r, op, rdest, rsrc); + gimple_seq_add_stmt (seq, stmt); + + stmt = gimple_build_assign (i, op, idest, isrc); + gimple_seq_add_stmt (seq, stmt); + } + else if (op == MULT_EXPR) + { + /* Let x = a + ib = dest, y = c + id = src. + x * y = (ac - bd) + i(ad + bc) */ + tree ac = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + tree bd = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + tree ad = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + tree bc = create_tmp_var (TREE_TYPE (TREE_TYPE (dest))); + + stmt = gimple_build_assign (ac, MULT_EXPR, rdest, rsrc); + gimple_seq_add_stmt (seq, stmt); + + stmt = gimple_build_assign (bd, MULT_EXPR, idest, isrc); + gimple_seq_add_stmt (seq, stmt); + + stmt = gimple_build_assign (r, MINUS_EXPR, ac, bd); + gimple_seq_add_stmt (seq, stmt); + + stmt = gimple_build_assign (ad, MULT_EXPR, rdest, isrc); + gimple_seq_add_stmt (seq, stmt); + + stmt = gimple_build_assign (bd, MULT_EXPR, idest, rsrc); + gimple_seq_add_stmt (seq, stmt); + + stmt = gimple_build_assign (i, PLUS_EXPR, ad, bc); + gimple_seq_add_stmt (seq, stmt); + } + else + gcc_unreachable (); + + result = build2 (COMPLEX_EXPR, TREE_TYPE (dest), r, i); + gimplify_assign (dest, result, seq); +} + +/* Helper function to initialize local data for the reduction arrays. + The reduction arrays need to be placed inside the calling function + for accelerators, or else the host won't be able to preform the final + reduction. */ + +static void +oacc_initialize_reduction_data (tree clauses, tree nthreads, + gimple_seq *stmt_seqp, omp_context *ctx) +{ + tree c, t, oc; + gimple stmt; + omp_context *octx; + + /* Find the innermost OpenACC parallel context. */ + if (gimple_code (ctx->stmt) == GIMPLE_OMP_TARGET + && (gimple_omp_target_kind (ctx->stmt) + == GF_OMP_TARGET_KIND_OACC_PARALLEL)) + octx = ctx; + else + octx = ctx->outer; + gcc_checking_assert (gimple_code (octx->stmt) == GIMPLE_OMP_TARGET + && (gimple_omp_target_kind (octx->stmt) + == GF_OMP_TARGET_KIND_OACC_PARALLEL)); + + /* Extract the clauses. */ + oc = gimple_omp_target_clauses (octx->stmt); + + /* Find the last outer clause. */ + for (; oc && OMP_CLAUSE_CHAIN (oc); oc = OMP_CLAUSE_CHAIN (oc)) + ; + + /* Allocate arrays for each reduction variable. */ + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + continue; + + tree var = OMP_CLAUSE_DECL (c); + tree type = get_base_type (var); + tree array = lookup_oacc_reduction (oacc_get_reduction_array_id (var), + ctx); + tree size, call; + + /* Calculate size of the reduction array. */ + t = create_tmp_var (TREE_TYPE (nthreads)); + stmt = gimple_build_assign (t, MULT_EXPR, nthreads, + fold_convert (TREE_TYPE (nthreads), + TYPE_SIZE_UNIT (type))); + gimple_seq_add_stmt (stmt_seqp, stmt); + + size = create_tmp_var (sizetype); + gimplify_assign (size, fold_build1 (NOP_EXPR, sizetype, t), stmt_seqp); + + /* Now allocate memory for it. */ + call = unshare_expr (builtin_decl_explicit (BUILT_IN_ALLOCA)); + stmt = gimple_build_call (call, 1, size); + gimple_call_set_lhs (stmt, array); + gimple_seq_add_stmt (stmt_seqp, stmt); + + /* Map this array into the accelerator. */ + + /* Add the reduction array to the list of clauses. */ + tree x = array; + t = build_omp_clause (gimple_location (ctx->stmt), OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (t, GOMP_MAP_FORCE_FROM); + OMP_CLAUSE_DECL (t) = x; + OMP_CLAUSE_CHAIN (t) = NULL; + if (oc) + OMP_CLAUSE_CHAIN (oc) = t; + else + gimple_omp_target_set_clauses (as_a <gomp_target *> (octx->stmt), t); + OMP_CLAUSE_SIZE (t) = size; + oc = t; + } +} + +/* Helper function to process the array of partial reductions. Nthreads + indicates the number of threads. Unfortunately, GOACC_GET_NUM_THREADS + cannot be used here, because nthreads on the host may be different than + on the accelerator. */ + +static void +oacc_finalize_reduction_data (tree clauses, tree nthreads, + gimple_seq *stmt_seqp, omp_context *ctx) +{ + tree c, x, var, array, loop_header, loop_body, loop_exit, type; + gimple stmt; + + /* Create for loop. + + let var = the original reduction variable + let array = reduction variable array + + for (i = 0; i < nthreads; i++) + var op= array[i] + */ + + loop_header = create_artificial_label (UNKNOWN_LOCATION); + loop_body = create_artificial_label (UNKNOWN_LOCATION); + loop_exit = create_artificial_label (UNKNOWN_LOCATION); + + /* Create and initialize an index variable. */ + tree ix = create_tmp_var (sizetype); + gimplify_assign (ix, fold_build1 (NOP_EXPR, sizetype, integer_zero_node), + stmt_seqp); + + /* Insert the loop header label here. */ + gimple_seq_add_stmt (stmt_seqp, gimple_build_label (loop_header)); + + /* Exit loop if ix >= nthreads. */ + x = create_tmp_var (sizetype); + gimplify_assign (x, fold_build1 (NOP_EXPR, sizetype, nthreads), stmt_seqp); + stmt = gimple_build_cond (GE_EXPR, ix, x, loop_exit, loop_body); + gimple_seq_add_stmt (stmt_seqp, stmt); + + /* Insert the loop body label here. */ + gimple_seq_add_stmt (stmt_seqp, gimple_build_label (loop_body)); + + /* Collapse each reduction array, one element at a time. */ + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_REDUCTION) + continue; + + tree_code reduction_code = OMP_CLAUSE_REDUCTION_CODE (c); + + /* reduction(-:var) sums up the partial results, so it acts + identically to reduction(+:var). */ + if (reduction_code == MINUS_EXPR) + reduction_code = PLUS_EXPR; + + /* Set up reduction variable var. */ + var = OMP_CLAUSE_DECL (c); + type = get_base_type (var); + array = lookup_oacc_reduction (oacc_get_reduction_array_id + (OMP_CLAUSE_DECL (c)), ctx); + + /* Calculate the array offset. */ + tree offset = create_tmp_var (sizetype); + gimplify_assign (offset, TYPE_SIZE_UNIT (type), stmt_seqp); + stmt = gimple_build_assign (offset, MULT_EXPR, offset, ix); + gimple_seq_add_stmt (stmt_seqp, stmt); + + tree ptr = create_tmp_var (TREE_TYPE (array)); + stmt = gimple_build_assign (ptr, POINTER_PLUS_EXPR, array, offset); + gimple_seq_add_stmt (stmt_seqp, stmt); + + /* Extract array[ix] into mem. */ + tree mem = create_tmp_var (type); + gimplify_assign (mem, build_simple_mem_ref (ptr), stmt_seqp); + + /* Find the original reduction variable. */ + if (is_reference (var)) + var = build_simple_mem_ref (var); + + tree t = create_tmp_var (type); + + x = lang_hooks.decls.omp_clause_assign_op (c, t, var); + gimplify_and_add (unshare_expr(x), stmt_seqp); + + /* var = var op mem */ + switch (OMP_CLAUSE_REDUCTION_CODE (c)) + { + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + t = fold_build2 (OMP_CLAUSE_REDUCTION_CODE (c), integer_type_node, + t, mem); + gimplify_and_add (t, stmt_seqp); + break; + default: + /* The lhs isn't a gimple_reg when var is COMPLEX_TYPE. */ + oacc_gimple_assign (t, OMP_CLAUSE_REDUCTION_CODE (c), mem, + stmt_seqp); + } + + t = fold_build1 (NOP_EXPR, TREE_TYPE (var), t); + x = lang_hooks.decls.omp_clause_assign_op (c, var, t); + gimplify_and_add (unshare_expr(x), stmt_seqp); + } + + /* Increment the induction variable. */ + tree one = fold_build1 (NOP_EXPR, sizetype, integer_one_node); + stmt = gimple_build_assign (ix, PLUS_EXPR, ix, one); + gimple_seq_add_stmt (stmt_seqp, stmt); + + /* Go back to the top of the loop. */ + gimple_seq_add_stmt (stmt_seqp, gimple_build_goto (loop_header)); + + /* Place the loop exit label here. */ + gimple_seq_add_stmt (stmt_seqp, gimple_build_label (loop_exit)); +} + +/* Scan through all of the gimple stmts searching for an OMP_FOR_EXPR, and + scan that for reductions. */ + +static void +oacc_process_reduction_data (gimple_seq *body, gimple_seq *in_stmt_seqp, + gimple_seq *out_stmt_seqp, omp_context *ctx) +{ + gimple_stmt_iterator gsi; + gimple_seq inner = NULL; + + /* A collapse clause may have inserted a new bind block. */ + gsi = gsi_start (*body); + while (!gsi_end_p (gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (gbind *bind_stmt = dyn_cast <gbind *> (stmt)) + { + inner = gimple_bind_body (bind_stmt); + body = &inner; + gsi = gsi_start (*body); + } + else if (dyn_cast <gomp_for *> (stmt)) + break; + else + gsi_next (&gsi); + } + + for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi)) + { + tree clauses, nthreads, t, c, acc_device, acc_device_host, call, + enter, exit; + bool reduction_found = false; + + gimple stmt = gsi_stmt (gsi); + + switch (gimple_code (stmt)) + { + case GIMPLE_OMP_FOR: + clauses = gimple_omp_for_clauses (stmt); + + /* Search for a reduction clause. */ + for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION) + { + reduction_found = true; + break; + } + + if (!reduction_found) + break; + + ctx = maybe_lookup_ctx (stmt); + t = NULL_TREE; + + /* Extract the number of threads. */ + nthreads = create_tmp_var (sizetype); + t = oacc_max_threads (ctx); + gimplify_assign (nthreads, t, in_stmt_seqp); + + /* Determine if this is kernel will be executed on the host. */ + call = builtin_decl_explicit (BUILT_IN_ACC_GET_DEVICE_TYPE); + acc_device = create_tmp_var (integer_type_node, ".acc_device_type"); + stmt = gimple_build_call (call, 0); + gimple_call_set_lhs (stmt, acc_device); + gimple_seq_add_stmt (in_stmt_seqp, stmt); + + /* Set nthreads = 1 for ACC_DEVICE_TYPE=host. */ + acc_device_host = create_tmp_var (integer_type_node, + ".acc_device_host"); + gimplify_assign (acc_device_host, + build_int_cst (integer_type_node, + GOMP_DEVICE_HOST), + in_stmt_seqp); + + enter = create_artificial_label (UNKNOWN_LOCATION); + exit = create_artificial_label (UNKNOWN_LOCATION); + + stmt = gimple_build_cond (EQ_EXPR, acc_device, acc_device_host, + enter, exit); + gimple_seq_add_stmt (in_stmt_seqp, stmt); + gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (enter)); + gimplify_assign (nthreads, fold_build1 (NOP_EXPR, sizetype, + integer_one_node), + in_stmt_seqp); + gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (exit)); + + /* Also, set nthreads = 1 for ACC_DEVICE_TYPE=host_nonshm. */ + gimplify_assign (acc_device_host, + build_int_cst (integer_type_node, + GOMP_DEVICE_HOST_NONSHM), + in_stmt_seqp); + + enter = create_artificial_label (UNKNOWN_LOCATION); + exit = create_artificial_label (UNKNOWN_LOCATION); + + stmt = gimple_build_cond (EQ_EXPR, acc_device, acc_device_host, + enter, exit); + gimple_seq_add_stmt (in_stmt_seqp, stmt); + gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (enter)); + gimplify_assign (nthreads, fold_build1 (NOP_EXPR, sizetype, + integer_one_node), + in_stmt_seqp); + gimple_seq_add_stmt (in_stmt_seqp, gimple_build_label (exit)); + + oacc_initialize_reduction_data (clauses, nthreads, in_stmt_seqp, + ctx); + oacc_finalize_reduction_data (clauses, nthreads, out_stmt_seqp, ctx); + break; + default: + // Scan for other directives which support reduction here. + break; + } + } +} /* If ctx is a worksharing context inside of a cancellable parallel region and it isn't nowait, add lhs to its GIMPLE_OMP_RETURN @@ -9389,7 +10424,7 @@ lower_omp_critical (gimple_stmt_iterator *gsi_p, omp_context *ctx) else decl = *n; - /* If '#pragma omp critical' is inside target region or + /* If '#pragma omp critical' is inside offloaded region or inside function marked as offloadable, the symbol must be marked as offloadable too. */ omp_context *octx; @@ -9397,7 +10432,7 @@ lower_omp_critical (gimple_stmt_iterator *gsi_p, omp_context *ctx) varpool_node::get_create (decl)->offloadable = 1; else for (octx = ctx->outer; octx; octx = octx->outer) - if (is_targetreg_ctx (octx)) + if (is_gimple_omp_offloaded (octx->stmt)) { varpool_node::get_create (decl)->offloadable = 1; break; @@ -9499,7 +10534,7 @@ lower_omp_for_lastprivate (struct omp_for_data *fd, gimple_seq *body_p, } -/* Lower code for an OpenMP loop directive. */ +/* Lower code for an OMP loop directive. */ static void lower_omp_for (gimple_stmt_iterator *gsi_p, omp_context *ctx) @@ -10140,7 +11175,7 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, omp_context *ctx) } } -/* Lower the OpenMP target directive in the current statement +/* Lower the GIMPLE_OMP_TARGET in the current statement in GSI_P. CTX holds context information for the directive. */ static void @@ -10149,24 +11184,52 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) tree clauses; tree child_fn, t, c; gomp_target *stmt = as_a <gomp_target *> (gsi_stmt (*gsi_p)); - gbind *tgt_bind = NULL, *bind; - gimple_seq tgt_body = NULL, olist, ilist, new_body; + gbind *tgt_bind, *bind; + gimple_seq tgt_body, olist, ilist, orlist, irlist, new_body; location_t loc = gimple_location (stmt); - int kind = gimple_omp_target_kind (stmt); + bool offloaded, data_region; unsigned int map_cnt = 0; + offloaded = is_gimple_omp_offloaded (stmt); + switch (gimple_omp_target_kind (stmt)) + { + case GF_OMP_TARGET_KIND_REGION: + case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: + case GF_OMP_TARGET_KIND_OACC_UPDATE: + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + data_region = false; + break; + case GF_OMP_TARGET_KIND_DATA: + case GF_OMP_TARGET_KIND_OACC_DATA: + data_region = true; + break; + default: + gcc_unreachable (); + } + clauses = gimple_omp_target_clauses (stmt); - if (kind == GF_OMP_TARGET_KIND_REGION) + + tgt_bind = NULL; + tgt_body = NULL; + if (offloaded) { tgt_bind = gimple_seq_first_stmt_as_a_bind (gimple_omp_body (stmt)); tgt_body = gimple_bind_body (tgt_bind); } - else if (kind == GF_OMP_TARGET_KIND_DATA) + else if (data_region) tgt_body = gimple_omp_body (stmt); child_fn = ctx->cb.dst_fn; push_gimplify_context (); + irlist = NULL; + orlist = NULL; + if (offloaded + && is_gimple_omp_oacc (stmt)) + oacc_process_reduction_data (&tgt_body, &irlist, &orlist, ctx); + for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) switch (OMP_CLAUSE_CODE (c)) { @@ -10175,6 +11238,31 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) default: break; case OMP_CLAUSE_MAP: +#ifdef ENABLE_CHECKING + /* First check what we're prepared to handle in the following. */ + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_POINTER: + case GOMP_MAP_TO_PSET: + break; + case GOMP_MAP_FORCE_ALLOC: + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_FORCE_PRESENT: + case GOMP_MAP_FORCE_DEALLOC: + case GOMP_MAP_FORCE_DEVICEPTR: + gcc_assert (is_gimple_omp_oacc (stmt)); + break; + default: + gcc_unreachable (); + } +#endif + /* FALLTHRU */ case OMP_CLAUSE_TO: case OMP_CLAUSE_FROM: var = OMP_CLAUSE_DECL (c); @@ -10199,12 +11287,11 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (!maybe_lookup_field (var, ctx)) continue; - if (kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded) { x = build_receiver_ref (var, true, ctx); tree new_var = lookup_decl (var, ctx); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) && TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE) x = build_simple_mem_ref (x); @@ -10214,16 +11301,16 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) map_cnt++; } - if (kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded) { target_nesting_level++; lower_omp (&tgt_body, ctx); target_nesting_level--; } - else if (kind == GF_OMP_TARGET_KIND_DATA) + else if (data_region) lower_omp (&tgt_body, ctx); - if (kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded) { /* Declare all the variables created by mapping and the variables declared in the scope of the target body. */ @@ -10247,9 +11334,20 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) DECL_NAMELESS (TREE_VEC_ELT (t, 1)) = 1; TREE_ADDRESSABLE (TREE_VEC_ELT (t, 1)) = 1; TREE_STATIC (TREE_VEC_ELT (t, 1)) = 1; + tree tkind_type; + int talign_shift; + if (is_gimple_omp_oacc (stmt)) + { + tkind_type = short_unsigned_type_node; + talign_shift = 8; + } + else + { + tkind_type = unsigned_char_type_node; + talign_shift = 3; + } TREE_VEC_ELT (t, 2) - = create_tmp_var (build_array_type_nelts (unsigned_char_type_node, - map_cnt), + = create_tmp_var (build_array_type_nelts (tkind_type, map_cnt), ".omp_data_kinds"); DECL_NAMELESS (TREE_VEC_ELT (t, 2)) = 1; TREE_ADDRESSABLE (TREE_VEC_ELT (t, 2)) = 1; @@ -10315,12 +11413,18 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) { tree var = lookup_decl_in_outer_ctx (ovar, ctx); tree x = build_sender_ref (ovar, ctx); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER - && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) - && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE) + if (maybe_lookup_oacc_reduction (var, ctx)) + { + gcc_checking_assert (offloaded + && is_gimple_omp_oacc (stmt)); + gimplify_assign (x, var, &ilist); + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c) + && TREE_CODE (TREE_TYPE (ovar)) == ARRAY_TYPE) { - gcc_assert (kind == GF_OMP_TARGET_KIND_REGION); + gcc_assert (offloaded); tree avar = create_tmp_var (TREE_TYPE (TREE_TYPE (x))); mark_addressable (avar); @@ -10331,16 +11435,19 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) } else if (is_gimple_reg (var)) { - gcc_assert (kind == GF_OMP_TARGET_KIND_REGION); + gcc_assert (offloaded); tree avar = create_tmp_var (TREE_TYPE (var)); mark_addressable (avar); - if (OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_ALLOC - && OMP_CLAUSE_MAP_KIND (c) != OMP_CLAUSE_MAP_FROM) + enum gomp_map_kind map_kind = OMP_CLAUSE_MAP_KIND (c); + if (GOMP_MAP_COPY_TO_P (map_kind) + || map_kind == GOMP_MAP_POINTER + || map_kind == GOMP_MAP_TO_PSET + || map_kind == GOMP_MAP_FORCE_DEVICEPTR) gimplify_assign (avar, var, &ilist); avar = build_fold_addr_expr (avar); gimplify_assign (x, avar, &ilist); - if ((OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_FROM - || OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_TOFROM) + if ((GOMP_MAP_COPY_FROM_P (map_kind) + || map_kind == GOMP_MAP_FORCE_DEVICEPTR) && !TYPE_READONLY (TREE_TYPE (var))) { x = build_sender_ref (ovar, ctx); @@ -10363,26 +11470,29 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (TREE_CODE (s) != INTEGER_CST) TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0; - unsigned char tkind = 0; + unsigned HOST_WIDE_INT tkind; switch (OMP_CLAUSE_CODE (c)) { case OMP_CLAUSE_MAP: tkind = OMP_CLAUSE_MAP_KIND (c); break; case OMP_CLAUSE_TO: - tkind = OMP_CLAUSE_MAP_TO; + tkind = GOMP_MAP_TO; break; case OMP_CLAUSE_FROM: - tkind = OMP_CLAUSE_MAP_FROM; + tkind = GOMP_MAP_FROM; break; default: gcc_unreachable (); } + gcc_checking_assert (tkind + < (HOST_WIDE_INT_C (1U) << talign_shift)); talign = ceil_log2 (talign); - tkind |= talign << 3; + tkind |= talign << talign_shift; + gcc_checking_assert (tkind + <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type))); CONSTRUCTOR_APPEND_ELT (vkind, purpose, - build_int_cst (unsigned_char_type_node, - tkind)); + build_int_cstu (tkind_type, tkind)); if (nc && nc != c) c = nc; } @@ -10420,7 +11530,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) new_body = NULL; - if (ctx->record_type && kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded + && ctx->record_type) { t = build_fold_addr_expr_loc (loc, ctx->sender_decl); /* fixup_child_record_type might have changed receiver_decl's type. */ @@ -10429,14 +11540,14 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) gimple_build_assign (ctx->receiver_decl, t)); } - if (kind == GF_OMP_TARGET_KIND_REGION) + if (offloaded) { gimple_seq_add_seq (&new_body, tgt_body); new_body = maybe_catch_exception (new_body); } - else if (kind == GF_OMP_TARGET_KIND_DATA) + else if (data_region) new_body = tgt_body; - if (kind != GF_OMP_TARGET_KIND_UPDATE) + if (offloaded || data_region) { gimple_seq_add_stmt (&new_body, gimple_build_omp_return (false)); gimple_omp_set_body (stmt, new_body); @@ -10446,9 +11557,11 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) tgt_bind ? gimple_bind_block (tgt_bind) : NULL_TREE); gsi_replace (gsi_p, bind, true); + gimple_bind_add_seq (bind, irlist); gimple_bind_add_seq (bind, ilist); gimple_bind_add_stmt (bind, stmt); gimple_bind_add_seq (bind, olist); + gimple_bind_add_seq (bind, orlist); pop_gimplify_context (NULL); } @@ -10520,7 +11633,7 @@ lower_omp_teams (gimple_stmt_iterator *gsi_p, omp_context *ctx) /* Callback for lower_omp_1. Return non-NULL if *tp needs to be regimplified. If DATA is non-NULL, lower_omp_1 is outside - of OpenMP context, but with task_shared_vars set. */ + of OMP context, but with task_shared_vars set. */ static tree lower_omp_regimplify_p (tree *tp, int *walk_subtrees, @@ -10560,7 +11673,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) memset (&wi, '\0', sizeof (wi)); /* If we have issued syntax errors, avoid doing any heavy lifting. - Just replace the OpenMP directives with a NOP to avoid + Just replace the OMP directives with a NOP to avoid confusing RTL expansion. */ if (seen_error () && is_gimple_omp (stmt)) { @@ -10747,8 +11860,8 @@ lower_omp (gimple_seq *body, omp_context *ctx) gimple_stmt_iterator gsi; for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi)) lower_omp_1 (&gsi, ctx); - /* During gimplification, we have not always invoked fold_stmt - (gimplify.c:maybe_fold_stmt); call it now. */ + /* During gimplification, we haven't folded statments inside offloading + regions (gimplify.c:maybe_fold_stmt); do that now. */ if (target_nesting_level) for (gsi = gsi_start (*body); !gsi_end_p (gsi); gsi_next (&gsi)) fold_stmt (&gsi); @@ -10765,8 +11878,9 @@ execute_lower_omp (void) omp_context *ctx; /* This pass always runs, to provide PROP_gimple_lomp. - But there is nothing to do unless -fopenmp is given. */ - if (flag_openmp == 0 && flag_openmp_simd == 0 && flag_cilkplus == 0) + But often, there is nothing to do. */ + if (flag_cilkplus == 0 && flag_openacc == 0 && flag_openmp == 0 + && flag_openmp_simd == 0) return 0; all_contexts = splay_tree_new (splay_tree_compare_pointers, 0, @@ -10832,7 +11946,7 @@ make_pass_lower_omp (gcc::context *ctxt) return new pass_lower_omp (ctxt); } -/* The following is a utility to diagnose OpenMP structured block violations. +/* The following is a utility to diagnose structured block violations. It is not part of the "omplower" pass, as that's invoked too late. It should be invoked by the respective front ends after gimplification. */ @@ -10845,9 +11959,38 @@ static bool diagnose_sb_0 (gimple_stmt_iterator *gsi_p, gimple branch_ctx, gimple label_ctx) { + gcc_checking_assert (!branch_ctx || is_gimple_omp (branch_ctx)); + gcc_checking_assert (!label_ctx || is_gimple_omp (label_ctx)); + if (label_ctx == branch_ctx) return false; + const char* kind = NULL; + + if (flag_cilkplus) + { + if ((branch_ctx + && gimple_code (branch_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (branch_ctx) == GF_OMP_FOR_KIND_CILKSIMD) + || (label_ctx + && gimple_code (label_ctx) == GIMPLE_OMP_FOR + && gimple_omp_for_kind (label_ctx) == GF_OMP_FOR_KIND_CILKSIMD)) + kind = "Cilk Plus"; + } + if (flag_openacc) + { + if ((branch_ctx && is_gimple_omp_oacc (branch_ctx)) + || (label_ctx && is_gimple_omp_oacc (label_ctx))) + { + gcc_checking_assert (kind == NULL); + kind = "OpenACC"; + } + } + if (kind == NULL) + { + gcc_checking_assert (flag_openmp); + kind = "OpenMP"; + } /* Previously we kept track of the label's entire context in diagnose_sb_[12] @@ -10880,45 +12023,25 @@ diagnose_sb_0 (gimple_stmt_iterator *gsi_p, } if (exit_p) - error ("invalid exit from OpenMP structured block"); + error ("invalid exit from %s structured block", kind); else - error ("invalid entry to OpenMP structured block"); + error ("invalid entry to %s structured block", kind); #endif - bool cilkplus_block = false; - if (flag_cilkplus) - { - if ((branch_ctx - && gimple_code (branch_ctx) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (branch_ctx) == GF_OMP_FOR_KIND_CILKSIMD) - || (label_ctx - && gimple_code (label_ctx) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (label_ctx) == GF_OMP_FOR_KIND_CILKSIMD)) - cilkplus_block = true; - } - /* If it's obvious we have an invalid entry, be specific about the error. */ if (branch_ctx == NULL) - { - if (cilkplus_block) - error ("invalid entry to Cilk Plus structured block"); - else - error ("invalid entry to OpenMP structured block"); - } + error ("invalid entry to %s structured block", kind); else { /* Otherwise, be vague and lazy, but efficient. */ - if (cilkplus_block) - error ("invalid branch to/from a Cilk Plus structured block"); - else - error ("invalid branch to/from an OpenMP structured block"); + error ("invalid branch to/from %s structured block", kind); } gsi_replace (gsi_p, gimple_build_nop (), false); return true; } -/* Pass 1: Create a minimal tree of OpenMP structured blocks, and record +/* Pass 1: Create a minimal tree of structured blocks, and record where each label is found. */ static tree @@ -10931,7 +12054,7 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, *handled_ops_p = true; - switch (gimple_code (stmt)) + switch (gimple_code (stmt)) { WALK_SUBSTMTS; @@ -11079,8 +12202,8 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, return NULL_TREE; } -/* Called from tree-cfg.c::make_edges to create cfg edges for all GIMPLE_OMP - codes. */ +/* Called from tree-cfg.c::make_edges to create cfg edges for all relevant + GIMPLE_* codes. */ bool make_gimple_omp_edges (basic_block bb, struct omp_region **region, int *region_idx) @@ -11109,8 +12232,22 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region, case GIMPLE_OMP_TARGET: cur_region = new_omp_region (bb, code, cur_region); fallthru = true; - if (gimple_omp_target_kind (last) == GF_OMP_TARGET_KIND_UPDATE) - cur_region = cur_region->outer; + switch (gimple_omp_target_kind (last)) + { + case GF_OMP_TARGET_KIND_REGION: + case GF_OMP_TARGET_KIND_DATA: + case GF_OMP_TARGET_KIND_OACC_PARALLEL: + case GF_OMP_TARGET_KIND_OACC_KERNELS: + case GF_OMP_TARGET_KIND_OACC_DATA: + break; + case GF_OMP_TARGET_KIND_UPDATE: + case GF_OMP_TARGET_KIND_OACC_UPDATE: + case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: + cur_region = cur_region->outer; + break; + default: + gcc_unreachable (); + } break; case GIMPLE_OMP_SECTIONS: @@ -11247,7 +12384,10 @@ public: {} /* opt_pass methods: */ - virtual bool gate (function *) { return flag_openmp || flag_cilkplus; } + virtual bool gate (function *) + { + return flag_cilkplus || flag_openacc || flag_openmp; + } virtual unsigned int execute (function *) { return diagnose_omp_structured_block_errors (); @@ -12515,7 +13655,7 @@ add_decls_addresses_to_decl_constructor (vec<tree, va_gc> *v_decls, /* 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 target regions. */ + functions, which are outlined offloading regions. */ void omp_finish_file (void) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d9525d5..885a710 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,133 @@ +2015-01-15 Thomas Schwinge <thomas@codesourcery.com> + James Norris <jnorris@codesourcery.com> + Cesar Philippidis <cesar@codesourcery.com> + Ilmir Usmanov <i.usmanov@samsung.com> + + * lib/target-supports.exp (check_effective_target_fopenacc): New + procedure. + * g++.dg/goacc-gomp/goacc-gomp.exp: New file. + * g++.dg/goacc/goacc.exp: Likewise. + * gcc.dg/goacc-gomp/goacc-gomp.exp: Likewise. + * gcc.dg/goacc/goacc.exp: Likewise. + * gfortran.dg/goacc/goacc.exp: Likewise. + * c-c++-common/cpp/openacc-define-1.c: New file. + * c-c++-common/cpp/openacc-define-2.c: Likewise. + * c-c++-common/cpp/openacc-define-3.c: Likewise. + * c-c++-common/goacc-gomp/nesting-1.c: Likewise. + * c-c++-common/goacc-gomp/nesting-fail-1.c: Likewise. + * c-c++-common/goacc/acc_on_device-2-off.c: Likewise. + * c-c++-common/goacc/acc_on_device-2.c: Likewise. + * c-c++-common/goacc/asyncwait-1.c: Likewise. + * c-c++-common/goacc/cache-1.c: Likewise. + * c-c++-common/goacc/clauses-fail.c: Likewise. + * c-c++-common/goacc/collapse-1.c: Likewise. + * c-c++-common/goacc/data-1.c: Likewise. + * c-c++-common/goacc/data-2.c: Likewise. + * c-c++-common/goacc/data-clause-duplicate-1.c: Likewise. + * c-c++-common/goacc/deviceptr-1.c: Likewise. + * c-c++-common/goacc/deviceptr-2.c: Likewise. + * c-c++-common/goacc/deviceptr-3.c: Likewise. + * c-c++-common/goacc/if-clause-1.c: Likewise. + * c-c++-common/goacc/if-clause-2.c: Likewise. + * c-c++-common/goacc/kernels-1.c: Likewise. + * c-c++-common/goacc/loop-1.c: Likewise. + * c-c++-common/goacc/loop-private-1.c: Likewise. + * c-c++-common/goacc/nesting-1.c: Likewise. + * c-c++-common/goacc/nesting-data-1.c: Likewise. + * c-c++-common/goacc/nesting-fail-1.c: Likewise. + * c-c++-common/goacc/parallel-1.c: Likewise. + * c-c++-common/goacc/pcopy.c: Likewise. + * c-c++-common/goacc/pcopyin.c: Likewise. + * c-c++-common/goacc/pcopyout.c: Likewise. + * c-c++-common/goacc/pcreate.c: Likewise. + * c-c++-common/goacc/pragma_context.c: Likewise. + * c-c++-common/goacc/present-1.c: Likewise. + * c-c++-common/goacc/reduction-1.c: Likewise. + * c-c++-common/goacc/reduction-2.c: Likewise. + * c-c++-common/goacc/reduction-3.c: Likewise. + * c-c++-common/goacc/reduction-4.c: Likewise. + * c-c++-common/goacc/sb-1.c: Likewise. + * c-c++-common/goacc/sb-2.c: Likewise. + * c-c++-common/goacc/sb-3.c: Likewise. + * c-c++-common/goacc/update-1.c: Likewise. + * gcc.dg/goacc/acc_on_device-1.c: Likewise. + * gfortran.dg/goacc/acc_on_device-1.f95: Likewise. + * gfortran.dg/goacc/acc_on_device-2-off.f95: Likewise. + * gfortran.dg/goacc/acc_on_device-2.f95: Likewise. + * gfortran.dg/goacc/assumed.f95: Likewise. + * gfortran.dg/goacc/asyncwait-1.f95: Likewise. + * gfortran.dg/goacc/asyncwait-2.f95: Likewise. + * gfortran.dg/goacc/asyncwait-3.f95: Likewise. + * gfortran.dg/goacc/asyncwait-4.f95: Likewise. + * gfortran.dg/goacc/branch.f95: Likewise. + * gfortran.dg/goacc/cache-1.f95: Likewise. + * gfortran.dg/goacc/coarray.f95: Likewise. + * gfortran.dg/goacc/continuation-free-form.f95: Likewise. + * gfortran.dg/goacc/cray.f95: Likewise. + * gfortran.dg/goacc/critical.f95: Likewise. + * gfortran.dg/goacc/data-clauses.f95: Likewise. + * gfortran.dg/goacc/data-tree.f95: Likewise. + * gfortran.dg/goacc/declare-1.f95: Likewise. + * gfortran.dg/goacc/enter-exit-data.f95: Likewise. + * gfortran.dg/goacc/fixed-1.f: Likewise. + * gfortran.dg/goacc/fixed-2.f: Likewise. + * gfortran.dg/goacc/fixed-3.f: Likewise. + * gfortran.dg/goacc/fixed-4.f: Likewise. + * gfortran.dg/goacc/host_data-tree.f95: Likewise. + * gfortran.dg/goacc/if.f95: Likewise. + * gfortran.dg/goacc/kernels-tree.f95: Likewise. + * gfortran.dg/goacc/list.f95: Likewise. + * gfortran.dg/goacc/literal.f95: Likewise. + * gfortran.dg/goacc/loop-1.f95: Likewise. + * gfortran.dg/goacc/loop-2.f95: Likewise. + * gfortran.dg/goacc/loop-3.f95: Likewise. + * gfortran.dg/goacc/loop-tree-1.f90: Likewise. + * gfortran.dg/goacc/omp.f95: Likewise. + * gfortran.dg/goacc/parallel-kernels-clauses.f95: Likewise. + * gfortran.dg/goacc/parallel-kernels-regions.f95: Likewise. + * gfortran.dg/goacc/parallel-tree.f95: Likewise. + * gfortran.dg/goacc/parameter.f95: Likewise. + * gfortran.dg/goacc/private-1.f95: Likewise. + * gfortran.dg/goacc/private-2.f95: Likewise. + * gfortran.dg/goacc/private-3.f95: Likewise. + * gfortran.dg/goacc/pure-elemental-procedures.f95: Likewise. + * gfortran.dg/goacc/reduction-2.f95: Likewise. + * gfortran.dg/goacc/reduction.f95: Likewise. + * gfortran.dg/goacc/routine-1.f90: Likewise. + * gfortran.dg/goacc/routine-2.f90: Likewise. + * gfortran.dg/goacc/sentinel-free-form.f95: Likewise. + * gfortran.dg/goacc/several-directives.f95: Likewise. + * gfortran.dg/goacc/sie.f95: Likewise. + * gfortran.dg/goacc/subarrays.f95: Likewise. + * gfortran.dg/gomp/map-1.f90: Likewise. + * gfortran.dg/openacc-define-1.f90: Likewise. + * gfortran.dg/openacc-define-2.f90: Likewise. + * gfortran.dg/openacc-define-3.f90: Likewise. + * g++.dg/gomp/block-1.C: Update for changed compiler output. + * g++.dg/gomp/block-2.C: Likewise. + * g++.dg/gomp/block-3.C: Likewise. + * g++.dg/gomp/block-5.C: Likewise. + * g++.dg/gomp/target-1.C: Likewise. + * g++.dg/gomp/target-2.C: Likewise. + * g++.dg/gomp/taskgroup-1.C: Likewise. + * g++.dg/gomp/teams-1.C: Likewise. + * gcc.dg/cilk-plus/jump-openmp.c: Likewise. + * gcc.dg/cilk-plus/jump.c: Likewise. + * gcc.dg/gomp/block-1.c: Likewise. + * gcc.dg/gomp/block-10.c: Likewise. + * gcc.dg/gomp/block-2.c: Likewise. + * gcc.dg/gomp/block-3.c: Likewise. + * gcc.dg/gomp/block-4.c: Likewise. + * gcc.dg/gomp/block-5.c: Likewise. + * gcc.dg/gomp/block-6.c: Likewise. + * gcc.dg/gomp/block-7.c: Likewise. + * gcc.dg/gomp/block-8.c: Likewise. + * gcc.dg/gomp/block-9.c: Likewise. + * gcc.dg/gomp/target-1.c: Likewise. + * gcc.dg/gomp/target-2.c: Likewise. + * gcc.dg/gomp/taskgroup-1.c: Likewise. + * gcc.dg/gomp/teams-1.c: Likewise. + 2015-01-15 David Malcolm <dmalcolm@redhat.com> * jit.dg/test-error-mismatching-types-in-assignment-op.c: New diff --git a/gcc/testsuite/c-c++-common/cpp/openacc-define-1.c b/gcc/testsuite/c-c++-common/cpp/openacc-define-1.c new file mode 100644 index 0000000..cd37548 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/openacc-define-1.c @@ -0,0 +1,6 @@ +/* { dg-do preprocess } */ +/* { dg-require-effective-target fopenacc } */ + +#ifdef _OPENACC +# error _OPENACC defined +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/openacc-define-2.c b/gcc/testsuite/c-c++-common/cpp/openacc-define-2.c new file mode 100644 index 0000000..b007e32 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/openacc-define-2.c @@ -0,0 +1,7 @@ +/* { dg-options "-fno-openacc" } */ +/* { dg-do preprocess } */ +/* { dg-require-effective-target fopenacc } */ + +#ifdef _OPENACC +# error _OPENACC defined +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/openacc-define-3.c b/gcc/testsuite/c-c++-common/cpp/openacc-define-3.c new file mode 100644 index 0000000..ccedcd9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/openacc-define-3.c @@ -0,0 +1,11 @@ +/* { dg-options "-fopenacc" } */ +/* { dg-do preprocess } */ +/* { dg-require-effective-target fopenacc } */ + +#ifndef _OPENACC +# error _OPENACC not defined +#endif + +#if _OPENACC != 201306 +# error _OPENACC defined to wrong value +#endif diff --git a/gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c new file mode 100644 index 0000000..df45bcf --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-1.c @@ -0,0 +1,12 @@ +void +f_omp_parallel (void) +{ +#pragma omp parallel + { + int i; + +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } +} diff --git a/gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c new file mode 100644 index 0000000..411fb5f --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc-gomp/nesting-fail-1.c @@ -0,0 +1,457 @@ +extern int i; + +void +f_omp (void) +{ +#pragma omp parallel + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + } + +#pragma omp for + for (i = 0; i < 3; i++) + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc loop /* { dg-error "may not be closely nested" } */ + for (i = 0; i < 2; ++i) + ; + } + +#pragma omp sections + { + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; + } +#pragma omp section + { +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; + } +#pragma omp section + { +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; + } +#pragma omp section + { +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + } +#pragma omp section + { +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + } +#pragma omp section + { +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + } +#pragma omp section + { +#pragma acc loop /* { dg-error "may not be closely nested" } */ + for (i = 0; i < 2; ++i) + ; + } + } + +#pragma omp single + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc loop /* { dg-error "may not be closely nested" } */ + for (i = 0; i < 2; ++i) + ; + } + +#pragma omp task + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc loop /* { dg-error "may not be closely nested" } */ + for (i = 0; i < 2; ++i) + ; + } + +#pragma omp master + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc loop /* { dg-error "may not be closely nested" } */ + for (i = 0; i < 2; ++i) + ; + } + +#pragma omp critical + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc loop /* { dg-error "may not be closely nested" } */ + for (i = 0; i < 2; ++i) + ; + } + +#pragma omp ordered + { +#pragma acc parallel /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc data /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC construct inside of non-OpenACC region" } */ +#pragma acc loop /* { dg-error "may not be closely nested" } */ + for (i = 0; i < 2; ++i) + ; + } + +#pragma omp target + { +#pragma acc parallel /* { dg-error "OpenACC parallel construct inside of OpenMP target region" } */ + ; +#pragma acc kernels /* { dg-error "OpenACC kernels construct inside of OpenMP target region" } */ + ; +#pragma acc data /* { dg-error "OpenACC data construct inside of OpenMP target region" } */ + ; +#pragma acc update host(i) /* { dg-error "OpenACC update construct inside of OpenMP target region" } */ +#pragma acc enter data copyin(i) /* { dg-error "OpenACC enter/exit data construct inside of OpenMP target region" } */ +#pragma acc exit data delete(i) /* { dg-error "OpenACC enter/exit data construct inside of OpenMP target region" } */ +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } +} + +void +f_acc_parallel (void) +{ +#pragma acc parallel + { +#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc parallel + { +#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + for (i = 0; i < 3; i++) + ; + } + +#pragma acc parallel + { +#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + { + ; + } + } + +#pragma acc parallel + { +#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc parallel + { +#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc parallel + { +#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc parallel + { +#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc parallel + { +#pragma omp atomic write + i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } + +#pragma acc parallel + { +#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc parallel + { +#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } +} + +void +f_acc_kernels (void) +{ +#pragma acc kernels + { +#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc kernels + { +#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + for (i = 0; i < 3; i++) + ; + } + +#pragma acc kernels + { +#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + { + ; + } + } + +#pragma acc kernels + { +#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc kernels + { +#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc kernels + { +#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc kernels + { +#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc kernels + { +#pragma omp atomic write + i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } + +#pragma acc kernels + { +#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc kernels + { +#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } +} + +void +f_acc_data (void) +{ +#pragma acc data + { +#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc data + { +#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + for (i = 0; i < 3; i++) + ; + } + +#pragma acc data + { +#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + { + ; + } + } + +#pragma acc data + { +#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc data + { +#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc data + { +#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc data + { +#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc data + { +#pragma omp atomic write + i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } + +#pragma acc data + { +#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc data + { +#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } +} + +void +f_acc_loop (void) +{ +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp parallel /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp for /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + for (i = 0; i < 3; i++) + ; + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp sections /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + { + ; + } + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp single /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp task /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp master /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp critical /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp atomic write + i = 0; /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp ordered /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; + } + +#pragma acc loop + for (i = 0; i < 2; ++i) + { +#pragma omp target /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target data /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + ; +#pragma omp target update to(i) /* { dg-error "non-OpenACC construct inside of OpenACC region" } */ + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/acc_on_device-2-off.c b/gcc/testsuite/c-c++-common/goacc/acc_on_device-2-off.c new file mode 100644 index 0000000..25d21ad --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/acc_on_device-2-off.c @@ -0,0 +1,25 @@ +/* Have to enable optimizations, as otherwise builtins won't be expanded. */ +/* { dg-additional-options "-O -fdump-rtl-expand -fno-openacc" } */ + +#if __cplusplus +extern "C" { +#endif + +typedef enum acc_device_t { acc_device_X = 123 } acc_device_t; +extern int acc_on_device (acc_device_t); + +#if __cplusplus +} +#endif + +int +f (void) +{ + const acc_device_t dev = acc_device_X; + return acc_on_device (dev); +} + +/* Without -fopenacc, we're expecting one call. + { dg-final { scan-rtl-dump-times "\\\(call \[^\\n\]*\\\"acc_on_device" 1 "expand" } } */ + +/* { dg-final { cleanup-rtl-dump "expand" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/acc_on_device-2.c b/gcc/testsuite/c-c++-common/goacc/acc_on_device-2.c new file mode 100644 index 0000000..d5389a9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/acc_on_device-2.c @@ -0,0 +1,29 @@ +/* Have to enable optimizations, as otherwise builtins won't be expanded. */ +/* { dg-additional-options "-O -fdump-rtl-expand" } */ + +#if __cplusplus +extern "C" { +#endif + +typedef enum acc_device_t { acc_device_X = 123 } acc_device_t; +extern int acc_on_device (acc_device_t); + +#if __cplusplus +} +#endif + +int +f (void) +{ + const acc_device_t dev = acc_device_X; + return acc_on_device (dev); +} + +/* With -fopenacc, we're expecting the builtin to be expanded, so no calls. + TODO: in C++, even under extern "C", the use of enum for acc_device_t + perturbs expansion as a builtin, which expects an int parameter. It's fine + when changing acc_device_t to plain int, but that's not what we're doing in + <openacc.h>. + { dg-final { scan-rtl-dump-times "\\\(call \[^\\n\]*\\\"acc_on_device" 0 "expand" { xfail c++ } } } */ + +/* { dg-final { cleanup-rtl-dump "expand" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/asyncwait-1.c b/gcc/testsuite/c-c++-common/goacc/asyncwait-1.c new file mode 100644 index 0000000..ccc0106 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/asyncwait-1.c @@ -0,0 +1,213 @@ +void +f (int N, float *a, float *b) +{ + int ii; + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (1 2) /* { dg-error "expected '\\)' before numeric constant" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (1,) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (,1) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (1,2,) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (1,2 3) /* { dg-error "expected '\\)' before numeric constant" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (1,2,,) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (1 /* { dg-error "expected '\\)' before end of line" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (*) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (a) + /* { dg-error "expected integer expression before" "" { target c } 54 } */ + /* { dg-error "'async' expression must be integral" "" { target c++ } 54 } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async (1.0) + /* { dg-error "expected integer expression before" "" { target c } 62 } */ + /* { dg-error "'async' expression must be integral" "" { target c++ } 62 } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async () /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) async + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1 2) /* { dg-error "expected '\\)' before numeric constant" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1,) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (,1) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1,2,) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1,2 3) /* { dg-error "expected '\\)' before numeric constant" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1,2,,) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1 /* { dg-error "expected '\\\)' before end of line" } */ + /* { dg-error "expected integer expression before '\\\)'" "" { target c++ } 118 } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1,*) /* { dg-error "expected (primary-|)expression before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1,a) /*{ dg-error "must be integral" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (a) /* { dg-error "must be integral" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait (1.0) /* { dg-error "must be integral" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait () /* { dg-error "expected (integer |)expression (list |)before" } */ + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc parallel copyin (a[0:N]) copy (b[0:N]) wait + { + for (ii = 0; ii < N; ii++) + b[ii] = a[ii]; + } + +#pragma acc wait (1 2) /* { dg-error "expected '\\)' before numeric constant" } */ + +#pragma acc wait (1,) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait (,1) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait (1,2,) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait (1,2 3) /* { dg-error "expected '\\)' before numeric constant" } */ + +#pragma acc wait (1,2,,) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait (1 /* { dg-error "expected '\\\)' before end of line" } */ + /* { dg-error "expected integer expression before '\\\)'" "" { target c++ } 173 } */ + +#pragma acc wait (1,*) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait (1,a) /* { dg-error "expression must be integral" } */ + +#pragma acc wait (a) /* { dg-error "expression must be integral" } */ + +#pragma acc wait (1.0) /* { dg-error "expression must be integral" } */ + +#pragma acc wait 1 /* { dg-error "expected '#pragma acc' clause before numeric constant" } */ + +#pragma acc wait N /* { dg-error "expected '#pragma acc' clause before 'N'" } */ + +#pragma acc wait async (1 2) /* { dg-error "expected '\\)' before numeric constant" } */ + +#pragma acc wait async (1 2) /* { dg-error "expected '\\)' before numeric constant" } */ + +#pragma acc wait async (1,) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait async (,1) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait async (1,2,) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait async (1,2 3) /* { dg-error "expected '\\)' before numeric constant" } */ + +#pragma acc wait async (1,2,,) /* { dg-error "expected (primary-|)expression before" } */ + +#pragma acc wait async (1 /* { dg-error "expected '\\)' before end of line" } */ + +#pragma acc wait async (*) /* { dg-error "expected (primary-|)expression before " } */ + +#pragma acc wait async (a) + /* { dg-error "expected integer expression before" "" { target c } 206 } */ + /* { dg-error "expression must be integral" "" { target c++ } 206 } */ + +#pragma acc wait async (1.0) + /* { dg-error "expected integer expression before" "" { target c } 210 } */ + /* { dg-error "expression must be integral" "" { target c++ } 210 } */ +} diff --git a/gcc/testsuite/c-c++-common/goacc/cache-1.c b/gcc/testsuite/c-c++-common/goacc/cache-1.c new file mode 100644 index 0000000..9503341 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/cache-1.c @@ -0,0 +1,88 @@ +int +main (int argc, char **argv) +{ +#define N 2 + int a[N], b[N]; + int i; + + for (i = 0; i < N; i++) + { + a[i] = 3; + b[i] = 0; + } + +#pragma acc parallel copyin (a[0:N]) copyout (b[0:N]) +{ + int ii; + + for (ii = 0; ii < N; ii++) + { + const int idx = ii; + int n = 1; + const int len = n; + +#pragma acc cache /* { dg-error "expected '\\\(' before end of line" } */ + +#pragma acc cache a[0:N] /* { dg-error "expected '\\\(' before 'a'" } */ + /* { dg-bogus "expected end of line before 'a'" "" { xfail c++ } 26 } */ + +#pragma acc cache (a) /* { dg-error "expected '\\\['" } */ + +#pragma acc cache ( /* { dg-error "expected (identifier|unqualified-id) before end of line" } */ + +#pragma acc cache () /* { dg-error "expected (identifier|unqualified-id) before '\\\)' token" } */ + +#pragma acc cache (,) /* { dg-error "expected (identifier|unqualified-id) before '(,|\\\))' token" } */ + +#pragma acc cache (a[0:N] /* { dg-error "expected '\\\)' before end of line" } */ + +#pragma acc cache (a[0:N],) /* { dg-error "expected (identifier|unqualified-id) before '(,|\\\))' token" "" { xfail c } } */ + +#pragma acc cache (a[0:N]) copyin (a[0:N]) /* { dg-error "expected end of line before 'copyin'" } */ + +#pragma acc cache () /* { dg-error "expected (identifier|unqualified-id) before '\\\)' token" } */ + +#pragma acc cache (a[0:N] b[0:N]) /* { dg-error "expected '\\\)' before 'b'" } */ + +#pragma acc cache (a[0:N] b[0:N}) /* { dg-error "expected '\\\)' before 'b'" } */ + /* { dg-bogus "expected end of line before '\\\}' token" "" { xfail c++ } 47 } */ + +#pragma acc cache (a[0:N] /* { dg-error "expected '\\\)' before end of line" } */ + +#pragma acc cache (a[ii]) /* { dg-error "'ii' is not a constant" } */ + +#pragma acc cache (a[idx:n]) /* { dg-error "'n' is not a constant" } */ + +#pragma acc cache (a[0:N]) ( /* { dg-error "expected end of line before '\\(' token" } */ + +#pragma acc cache (a[0:N]) ii /* { dg-error "expected end of line before 'ii'" } */ + +#pragma acc cache (a[0:N] ii) /* { dg-error "expected '\\)' before 'ii'" } */ + +#pragma acc cache (a[0:N]) + +#pragma acc cache (a[0:N], a[0:N]) + +#pragma acc cache (a[0:N], b[0:N]) + +#pragma acc cache (a[0]) + +#pragma acc cache (a[0], a[1], b[0:N]) + +#pragma acc cache (a[idx]) + +#pragma acc cache (a[idx:len]) + + b[ii] = a[ii]; + } +} + + + for (i = 0; i < N; i++) + { + if (a[i] != b[i]) + __builtin_abort (); + } + + return 0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/clauses-fail.c b/gcc/testsuite/c-c++-common/goacc/clauses-fail.c new file mode 100644 index 0000000..8990180 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/clauses-fail.c @@ -0,0 +1,18 @@ +void +f (void) +{ + int i; + +#pragma acc parallel one /* { dg-error "expected '#pragma acc' clause before 'one'" } */ + ; + +#pragma acc kernels eins /* { dg-error "expected '#pragma acc' clause before 'eins'" } */ + ; + +#pragma acc data two /* { dg-error "expected '#pragma acc' clause before 'two'" } */ + ; + +#pragma acc loop deux /* { dg-error "expected '#pragma acc' clause before 'deux'" } */ + for (i = 0; i < 2; ++i) + ; +} diff --git a/gcc/testsuite/c-c++-common/goacc/collapse-1.c b/gcc/testsuite/c-c++-common/goacc/collapse-1.c new file mode 100644 index 0000000..11b1438 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/collapse-1.c @@ -0,0 +1,97 @@ +/* { dg-skip-if "not yet" { c++ } } */ + +int i, j, k; +extern int foo (void); + +void +f1 (void) +{ + #pragma acc parallel + #pragma acc loop collapse (2) + for (i = 0; i < 5; i++) + ; /* { dg-error "not enough perfectly nested" } */ + { + for (j = 0; j < 5; j++) + ; + } +} + +void +f2 (void) +{ + #pragma acc parallel + #pragma acc loop collapse (2) + for (i = 0; i < 5; i++) + { + { + { + for (j = 0; j < 5; j++) + { + } + } + } + } +} + +void +f3 (void) +{ + #pragma acc parallel + #pragma acc loop collapse (2) + for (i = 0; i < 5; i++) + { + int k = foo (); /* { dg-error "not enough perfectly nested" } */ + { + { + for (j = 0; j < 5; j++) + { + } + } + } + } +} + +void +f4 (void) +{ + #pragma acc parallel + #pragma acc loop collapse (2) + for (i = 0; i < 5; i++) + { + { + for (j = 0; j < 5; j++) + ; + foo (); /* { dg-error "collapsed loops not perfectly nested before" } */ + } + } +} + +void +f5 (void) +{ + #pragma acc parallel + #pragma acc loop collapse (2) + for (i = 0; i < 5; i++) + { + { + for (j = 0; j < 5; j++) + ; + } + foo (); /* { dg-error "collapsed loops not perfectly nested before" } */ + } +} + +void +f6 (void) +{ + #pragma acc parallel + #pragma acc loop collapse (2) + for (i = 0; i < 5; i++) + { + { + for (j = 0; j < 5; j++) + ; + } + } + foo (); +} diff --git a/gcc/testsuite/c-c++-common/goacc/data-1.c b/gcc/testsuite/c-c++-common/goacc/data-1.c new file mode 100644 index 0000000..8094575 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/data-1.c @@ -0,0 +1,6 @@ +void +foo (void) +{ +#pragma acc data + ; +} diff --git a/gcc/testsuite/c-c++-common/goacc/data-2.c b/gcc/testsuite/c-c++-common/goacc/data-2.c new file mode 100644 index 0000000..a67d8a4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/data-2.c @@ -0,0 +1,21 @@ +void +foo (void) +{ + int a, b[100]; + int n; +#pragma acc enter data copyin (a, b) async wait +#pragma acc enter data create (b[20:30]) async wait +#pragma acc enter data (a) /* { dg-error "expected '#pragma acc' clause before '\\\(' token" } */ +#pragma acc enter data create (b(1:10)) /* { dg-error "expected '\\\)' before '\\\(' token" } */ +#pragma acc exit data delete (a) if (0) +#pragma acc exit data copyout (b) if (a) +#pragma acc exit data delete (b) +#pragma acc enter /* { dg-error "expected 'data' in" } */ +#pragma acc exit /* { dg-error "expected 'data' in" } */ +#pragma acc enter data /* { dg-error "has no data movement clause" } */ +#pragma acc exit data /* { dg-error "has no data movement clause" } */ +#pragma acc enter Data /* { dg-error "invalid pragma before" } */ +#pragma acc exit copyout (b) /* { dg-error "invalid pragma before" } */ +} + +/* { dg-error "has no data movement clause" "" { target *-*-* } 8 } */ diff --git a/gcc/testsuite/c-c++-common/goacc/data-clause-duplicate-1.c b/gcc/testsuite/c-c++-common/goacc/data-clause-duplicate-1.c new file mode 100644 index 0000000..7a1cf68 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/data-clause-duplicate-1.c @@ -0,0 +1,13 @@ +void +fun (void) +{ + float *fp; +#pragma acc parallel copy(fp[0:2],fp[0:2]) /* { dg-error "'fp' appears more than once in map clauses" } */ + ; +#pragma acc kernels present_or_copyin(fp[3]) present_or_copyout(fp[7:4]) /* { dg-error "'fp' appears more than once in map clauses" } */ + ; +#pragma acc data create(fp[:10]) deviceptr(fp) /* { dg-error "'fp' appears more than once in map clauses" } */ + ; +#pragma acc data create(fp) present(fp) /* { dg-error "'fp' appears more than once in map clauses" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/goacc/deviceptr-1.c b/gcc/testsuite/c-c++-common/goacc/deviceptr-1.c new file mode 100644 index 0000000..546fa82 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/deviceptr-1.c @@ -0,0 +1,86 @@ +/* { dg-skip-if "not yet" { c++ } } */ + +void +fun1 (void) +{ +#pragma acc parallel deviceptr(u) /* { dg-error "'u' undeclared" } */ + ; +#pragma acc kernels deviceptr(u[0:4]) /* { dg-error "expected '\\\)' before '\\\[' token" } */ + ; + +#pragma acc data deviceptr(fun1) /* { dg-error "'fun1' is not a variable" } */ + ; +#pragma acc parallel deviceptr(fun1[2:5]) + /* { dg-error "'fun1' is not a variable" "not a variable" { target *-*-* } 13 } */ + /* { dg-error "expected '\\\)' before '\\\[' token" "array" { target *-*-* } 13 } */ + ; + + int i; +#pragma acc kernels deviceptr(i) /* { dg-error "'i' is not a pointer variable" } */ + ; +#pragma acc data deviceptr(i[0:4]) + /* { dg-error "'i' is not a pointer variable" "not a pointer variable" { target *-*-* } 21 } */ + /* { dg-error "expected '\\\)' before '\\\[' token" "array" { target *-*-* } 21 } */ + ; + + float fa[10]; +#pragma acc parallel deviceptr(fa) /* { dg-error "'fa' is not a pointer variable" } */ + ; +#pragma acc kernels deviceptr(fa[1:5]) + /* { dg-error "'fa' is not a pointer variable" "not a pointer variable" { target *-*-* } 29 } */ + /* { dg-error "expected '\\\)' before '\\\[' token" "array" { target *-*-* } 29 } */ + ; + + float *fp; +#pragma acc data deviceptr(fp) + ; +#pragma acc parallel deviceptr(fp[0:4]) /* { dg-error "expected '\\\)' before '\\\[' token" } */ + ; +} + +void +fun2 (void) +{ + int i; + float *fp; +#pragma acc kernels deviceptr(fp,u,fun2,i,fp) + /* { dg-error "'u' undeclared" "u undeclared" { target *-*-* } 46 } */ + /* { dg-error "'fun2' is not a variable" "fun2 not a variable" { target *-*-* } 46 } */ + /* { dg-error "'i' is not a pointer variable" "i not a pointer variable" { target *-*-* } 46 } */ + /* { dg-error "'fp' appears more than once in map clauses" "fp more than once" { target *-*-* } 46 } */ + ; +} + +void +fun3 (void) +{ + float *fp; +#pragma acc data deviceptr(fp,fp) /* { dg-error "'fp' appears more than once in map clauses" } */ + ; +#pragma acc parallel deviceptr(fp) deviceptr(fp) /* { dg-error "'fp' appears more than once in map clauses" } */ + ; +#pragma acc kernels copy(fp) deviceptr(fp) /* { dg-error "'fp' appears more than once in map clauses" } */ + ; +} + +extern struct s s1; +extern struct s s2[1]; /* { dg-error "array type has incomplete element type" "" { target c } } */ + +void +fun4 (void) +{ + struct s *s1_p = &s1; + struct s *s2_p = &s2; + +#pragma acc parallel deviceptr(s1) /* { dg-error "'s1' is not a pointer variable" } */ + ; + +#pragma acc parallel deviceptr(s2) + ; + +#pragma acc parallel deviceptr(s1_p) + s1_p = 0; + +#pragma acc parallel deviceptr(s2_p) + s2_p = 0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/deviceptr-2.c b/gcc/testsuite/c-c++-common/goacc/deviceptr-2.c new file mode 100644 index 0000000..ac162b4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/deviceptr-2.c @@ -0,0 +1,23 @@ +void +fun1 (void) +{ + char *a = 0; + +#pragma acc data deviceptr(a) + ++a; + +#pragma acc data deviceptr(a) +#pragma acc parallel + ++a; + +#pragma acc data deviceptr(a) +#pragma acc parallel deviceptr(a) + ++a; + +#pragma acc data +#pragma acc parallel deviceptr(a) + ++a; + +#pragma acc parallel deviceptr(a) + ++a; +} diff --git a/gcc/testsuite/c-c++-common/goacc/deviceptr-3.c b/gcc/testsuite/c-c++-common/goacc/deviceptr-3.c new file mode 100644 index 0000000..bab56c3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/deviceptr-3.c @@ -0,0 +1,11 @@ +float *d_a; + +void +f (float *a) +{ +#pragma acc parallel copyout (a[3:10]) deviceptr (d_a) + d_a[2] += 1.0; + +#pragma acc parallel deviceptr (d_a) copyout (a[3:10]) + d_a[2] += 1.0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/if-clause-1.c b/gcc/testsuite/c-c++-common/goacc/if-clause-1.c new file mode 100644 index 0000000..85abf165 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/if-clause-1.c @@ -0,0 +1,10 @@ +/* { dg-skip-if "not yet" { c++ } } */ + +void +f (void) +{ + struct { int i; } *p; +#pragma acc data copyout(p) if(1) if(1) /* { dg-error "too many 'if' clauses" } */ + ; +#pragma acc update device(p) if(*p) /* { dg-error "used struct type value where scalar is required" } */ +} diff --git a/gcc/testsuite/c-c++-common/goacc/if-clause-2.c b/gcc/testsuite/c-c++-common/goacc/if-clause-2.c new file mode 100644 index 0000000..5ab8459 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/if-clause-2.c @@ -0,0 +1,11 @@ +void +f (short c) +{ +#pragma acc parallel if(c) + ; +#pragma acc kernels if(c) + ; +#pragma acc data if(c) + ; +#pragma acc update device(c) if(c) +} diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-1.c b/gcc/testsuite/c-c++-common/goacc/kernels-1.c new file mode 100644 index 0000000..e91b81c --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/kernels-1.c @@ -0,0 +1,6 @@ +void +foo (void) +{ +#pragma acc kernels + ; +} diff --git a/gcc/testsuite/c-c++-common/goacc/loop-1.c b/gcc/testsuite/c-c++-common/goacc/loop-1.c new file mode 100644 index 0000000..fea40e0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/loop-1.c @@ -0,0 +1,72 @@ +/* { dg-skip-if "not yet" { c++ } } */ + +int test1() +{ + int i, j, k, b[10]; + int a[30]; + double d; + float r; + i = 0; + #pragma acc loop + while(1) /* { dg-error "for statement expected" } */ + { + if (i > 0) break; + i = i + 1; + } + i = 0; + #pragma acc loop + for(;;) /* { dg-error "expected iteration declaration or initialization" } */ + { + if (i > 0) break; /* { dg-error "break statement used" } */ + i = i + 1; + } + i = 0; + #pragma acc loop + do /* { dg-error "for statement expected" } */ + { + i = i + 1; + } + while (i < 4); + #pragma acc loop + while (i < 8) /* { dg-error "for statement expected" } */ + { + i = i + 1; + } + #pragma acc loop + for (d = 1; d < 30; d+= 6) /* { dg-error "invalid type for iteration variable" } */ + { + i = d; + a[i] = 1; + } + #pragma acc loop + for (i = 1; i < 30; i++ ) + if (i == 16) break; /* { dg-error "break statement used" } */ + +/* different types of for loop are allowed */ + #pragma acc loop + for (i = 1; i < 10; i++) + { + } + #pragma acc loop + for (i = 1; i < 10; i+=2) + { + a[i] = i; + } + + /* after loop directive must be loop */ + #pragma acc loop + a[1] = 1; /* { dg-error "for statement expected" } */ + for (i = 1; i < 10; i++) + ; + /* combined directives may be used*/ + #pragma acc parallel loop + for(i = 1; i < 10; i++) + { + } + #pragma acc kernels loop + for(i = 1; i < 10; i++) + { + } + return 0; +} +/* { dg-prune-output "sorry, unimplemented: directive not yet implemented" } */ diff --git a/gcc/testsuite/c-c++-common/goacc/loop-private-1.c b/gcc/testsuite/c-c++-common/goacc/loop-private-1.c new file mode 100644 index 0000000..a54edb2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/loop-private-1.c @@ -0,0 +1,14 @@ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +void +f (int i, int j) +{ +#pragma acc kernels +#pragma acc loop collapse(2) + for (i = 0; i < 20; ++i) + for (j = 0; j < 25; ++j) + ; +} + +/* { dg-final { scan-tree-dump-times "#pragma acc loop collapse\\(2\\) private\\(j\\) private\\(i\\)" 1 "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/nesting-1.c b/gcc/testsuite/c-c++-common/goacc/nesting-1.c new file mode 100644 index 0000000..b4b863f --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/nesting-1.c @@ -0,0 +1,101 @@ +extern int i; + +void +f_acc_parallel (void) +{ +#pragma acc parallel + { +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } +} + + +void +f_acc_kernels (void) +{ +#pragma acc kernels + { +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } +} + + +void +f_acc_data (void) +{ +#pragma acc data + { +#pragma acc parallel + ; + +#pragma acc parallel + { +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } + +#pragma acc kernels + ; + +#pragma acc kernels + { +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } + +#pragma acc data + ; + +#pragma acc update host(i) + +#pragma acc enter data copyin(i) + +#pragma acc exit data delete(i) + +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + +#pragma acc data + { +#pragma acc parallel + ; + +#pragma acc parallel + { +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } + +#pragma acc kernels + ; + +#pragma acc kernels + { +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } + +#pragma acc data + ; + +#pragma acc update host(i) + +#pragma acc enter data copyin(i) + +#pragma acc exit data delete(i) + +#pragma acc loop + for (i = 0; i < 2; ++i) + ; + } + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/nesting-data-1.c b/gcc/testsuite/c-c++-common/goacc/nesting-data-1.c new file mode 100644 index 0000000..fefe6cd --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/nesting-data-1.c @@ -0,0 +1,61 @@ +void +f (void) +{ + unsigned char c, ca[15], caa[20][30]; + +#pragma acc data copyin(c) + { + c = 5; + ca[3] = c; + caa[3][12] = ca[3] + caa[3][12]; + +#pragma acc data copyin(ca[2:4]) + { + c = 6; + ca[4] = c; + caa[3][12] = ca[3] + caa[3][12]; + } + +#pragma acc parallel copyout(ca[3:4]) + { + c = 7; + ca[5] = c; + caa[3][12] = ca[3] + caa[3][12]; + } + +#pragma acc kernels copy(ca[4:4]) + { + c = 8; + ca[6] = c; + caa[3][12] = ca[3] + caa[3][12]; + } + +#pragma acc data pcopy(ca[5:7]) + { + c = 15; + ca[7] = c; + caa[3][12] = ca[3] + caa[3][12]; + +#pragma acc data pcopyin(caa[3:7][0:30]) + { + c = 16; + ca[8] = c; + caa[3][12] = ca[3] + caa[3][12]; + } + +#pragma acc parallel pcopyout(caa[3:7][0:30]) + { + c = 17; + ca[9] = c; + caa[3][12] = ca[3] + caa[3][12]; + } + +#pragma acc kernels pcopy(caa[3:7][0:30]) + { + c = 18; + ca[10] = c; + caa[3][12] = ca[3] + caa[3][12]; + } + } + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c b/gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c new file mode 100644 index 0000000..8af1c82 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/nesting-fail-1.c @@ -0,0 +1,39 @@ +extern int i; + +/* While the OpenACC specification does allow for certain kinds of + nesting, we don't support many of these yet. */ +void +f_acc_parallel (void) +{ +#pragma acc parallel + { +#pragma acc parallel /* { dg-bogus "parallel construct inside of parallel region" "not implemented" { xfail *-*-* } } */ + ; +#pragma acc kernels /* { dg-bogus "kernels construct inside of parallel region" "not implemented" { xfail *-*-* } } */ + ; +#pragma acc data /* { dg-error "data construct inside of parallel region" } */ + ; +#pragma acc update host(i) /* { dg-error "update construct inside of parallel region" } */ +#pragma acc enter data copyin(i) /* { dg-error "enter/exit data construct inside of parallel region" } */ +#pragma acc exit data delete(i) /* { dg-error "enter/exit data construct inside of parallel region" } */ + } +} + +/* While the OpenACC specification does allow for certain kinds of + nesting, we don't support many of these yet. */ +void +f_acc_kernels (void) +{ +#pragma acc kernels + { +#pragma acc parallel /* { dg-bogus "parallel construct inside of kernels region" "not implemented" { xfail *-*-* } } */ + ; +#pragma acc kernels /* { dg-bogus "kernels construct inside of kernels region" "not implemented" { xfail *-*-* } } */ + ; +#pragma acc data /* { dg-error "data construct inside of kernels region" } */ + ; +#pragma acc update host(i) /* { dg-error "update construct inside of kernels region" } */ +#pragma acc enter data copyin(i) /* { dg-error "enter/exit data construct inside of kernels region" } */ +#pragma acc exit data delete(i) /* { dg-error "enter/exit data construct inside of kernels region" } */ + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/parallel-1.c b/gcc/testsuite/c-c++-common/goacc/parallel-1.c new file mode 100644 index 0000000..a860526 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/parallel-1.c @@ -0,0 +1,6 @@ +void +foo (void) +{ +#pragma acc parallel + ; +} diff --git a/gcc/testsuite/c-c++-common/goacc/pcopy.c b/gcc/testsuite/c-c++-common/goacc/pcopy.c new file mode 100644 index 0000000..fd16525 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/pcopy.c @@ -0,0 +1,11 @@ +/* { dg-additional-options "-fdump-tree-original" } */ + +void +f (char *cp) +{ +#pragma acc parallel pcopy(cp[3:5]) + ; +} + +/* { dg-final { scan-tree-dump-times "#pragma acc parallel map\\(tofrom:\\*\\(cp \\+ 3\\) \\\[len: 5]\\) map\\(alloc:cp \\\[pointer assign, bias: 3]\\)" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/pcopyin.c b/gcc/testsuite/c-c++-common/goacc/pcopyin.c new file mode 100644 index 0000000..c009d24 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/pcopyin.c @@ -0,0 +1,11 @@ +/* { dg-additional-options "-fdump-tree-original" } */ + +void +f (char *cp) +{ +#pragma acc parallel pcopyin(cp[4:6]) + ; +} + +/* { dg-final { scan-tree-dump-times "#pragma acc parallel map\\(to:\\*\\(cp \\+ 4\\) \\\[len: 6]\\) map\\(alloc:cp \\\[pointer assign, bias: 4]\\)" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/pcopyout.c b/gcc/testsuite/c-c++-common/goacc/pcopyout.c new file mode 100644 index 0000000..6099eff --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/pcopyout.c @@ -0,0 +1,11 @@ +/* { dg-additional-options "-fdump-tree-original" } */ + +void +f (char *cp) +{ +#pragma acc parallel pcopyout(cp[5:7]) + ; +} + +/* { dg-final { scan-tree-dump-times "#pragma acc parallel map\\(from:\\*\\(cp \\+ 5\\) \\\[len: 7]\\) map\\(alloc:cp \\\[pointer assign, bias: 5]\\)" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/pcreate.c b/gcc/testsuite/c-c++-common/goacc/pcreate.c new file mode 100644 index 0000000..2f6e836e6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/pcreate.c @@ -0,0 +1,11 @@ +/* { dg-additional-options "-fdump-tree-original" } */ + +void +f (char *cp) +{ +#pragma acc parallel pcreate(cp[6:8]) + ; +} + +/* { dg-final { scan-tree-dump-times "#pragma acc parallel map\\(alloc:\\*\\(cp \\+ 6\\) \\\[len: 8]\\) map\\(alloc:cp \\\[pointer assign, bias: 6]\\)" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/pragma_context.c b/gcc/testsuite/c-c++-common/goacc/pragma_context.c new file mode 100644 index 0000000..680dc9b --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/pragma_context.c @@ -0,0 +1,34 @@ +/* { dg-skip-if "not yet" { c++ } } */ + +// pragma_external +#pragma acc update /* { dg-error "expected declaration specifiers before '#pragma'" } */ + +// pragma_struct +struct s_pragma_struct +{ +#pragma acc update /* { dg-error "expected declaration specifiers before '#pragma'" } */ +}; + +// pragma_param +void +f_pragma_param ( +#pragma acc update /* { dg-error "expected declaration specifiers before '#pragma'" } */ + void) +{ +} + +// pragma_stmt +void +f2 (void) +{ + if (0) +#pragma acc update /* { dg-error "'#pragma acc update' may only be used in compound statements before '#pragma'" } */ +} + +// pragma_compound +void +f3 (void) +{ + int i = 0; +#pragma acc update device(i) +} diff --git a/gcc/testsuite/c-c++-common/goacc/present-1.c b/gcc/testsuite/c-c++-common/goacc/present-1.c new file mode 100644 index 0000000..03ee592 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/present-1.c @@ -0,0 +1,11 @@ +/* { dg-additional-options "-fdump-tree-original" } */ + +void +f (char *cp) +{ +#pragma acc parallel present(cp[7:9]) + ; +} + +/* { dg-final { scan-tree-dump-times "#pragma acc parallel map\\(force_present:\\*\\(cp \\+ 7\\) \\\[len: 9]\\) map\\(alloc:cp \\\[pointer assign, bias: 7]\\)" 1 "original" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-1.c b/gcc/testsuite/c-c++-common/goacc/reduction-1.c new file mode 100644 index 0000000..0f50082 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-1.c @@ -0,0 +1,71 @@ +/* Integer reductions. */ + +#define vl 32 + +int +main(void) +{ + const int n = 1000; + int i; + int result, array[n]; + int lresult; + + /* '+' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (+:result) + for (i = 0; i < n; i++) + result += array[i]; + + /* '*' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (*:result) + for (i = 0; i < n; i++) + result *= array[i]; + +// result = 0; +// vresult = 0; +// +// /* 'max' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result > array[i] ? result : array[i]; +// +// /* 'min' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result < array[i] ? result : array[i]; + + /* '&' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (&:result) + for (i = 0; i < n; i++) + result &= array[i]; + + /* '|' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (|:result) + for (i = 0; i < n; i++) + result |= array[i]; + + /* '^' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (^:result) + for (i = 0; i < n; i++) + result ^= array[i]; + + /* '&&' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (&&:lresult) + for (i = 0; i < n; i++) + lresult = lresult && (result > array[i]); + + /* '||' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (||:lresult) + for (i = 0; i < n; i++) + lresult = lresult || (result > array[i]); + + return 0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-2.c b/gcc/testsuite/c-c++-common/goacc/reduction-2.c new file mode 100644 index 0000000..1f95138 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-2.c @@ -0,0 +1,50 @@ +/* float reductions. */ + +#define vl 32 + +int +main(void) +{ + const int n = 1000; + int i; + float result, array[n]; + int lresult; + + /* '+' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (+:result) + for (i = 0; i < n; i++) + result += array[i]; + + /* '*' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (*:result) + for (i = 0; i < n; i++) + result *= array[i]; + +// /* 'max' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result > array[i] ? result : array[i]; +// +// /* 'min' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result < array[i] ? result : array[i]; + + /* '&&' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (&&:lresult) + for (i = 0; i < n; i++) + lresult = lresult && (result > array[i]); + + /* '||' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (||:lresult) + for (i = 0; i < n; i++) + lresult = lresult || (result > array[i]); + + return 0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-3.c b/gcc/testsuite/c-c++-common/goacc/reduction-3.c new file mode 100644 index 0000000..476e375 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-3.c @@ -0,0 +1,50 @@ +/* double reductions. */ + +#define vl 32 + +int +main(void) +{ + const int n = 1000; + int i; + double result, array[n]; + int lresult; + + /* '+' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (+:result) + for (i = 0; i < n; i++) + result += array[i]; + + /* '*' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (*:result) + for (i = 0; i < n; i++) + result *= array[i]; + +// /* 'max' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result > array[i] ? result : array[i]; +// +// /* 'min' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result < array[i] ? result : array[i]; + + /* '&&' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (&&:lresult) + for (i = 0; i < n; i++) + lresult = lresult && (result > array[i]); + + /* '||' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (||:lresult) + for (i = 0; i < n; i++) + lresult = lresult || (result > array[i]); + + return 0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/reduction-4.c b/gcc/testsuite/c-c++-common/goacc/reduction-4.c new file mode 100644 index 0000000..73dde86 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/reduction-4.c @@ -0,0 +1,52 @@ +/* complex reductions. */ + +#define vl 32 + +int +main(void) +{ + const int n = 1000; + int i; + __complex__ double result, array[n]; + int lresult; + + /* '+' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (+:result) + for (i = 0; i < n; i++) + result += array[i]; + + /* Needs support for complex multiplication. */ + +// /* '*' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (*:result) +// for (i = 0; i < n; i++) +// result *= array[i]; +// +// /* 'max' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result > array[i] ? result : array[i]; +// +// /* 'min' reductions. */ +// #pragma acc parallel vector_length (vl) +// #pragma acc loop reduction (+:result) +// for (i = 0; i < n; i++) +// result = result < array[i] ? result : array[i]; + + /* '&&' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (&&:lresult) + for (i = 0; i < n; i++) + lresult = lresult && (__real__(result) > __real__(array[i])); + + /* '||' reductions. */ +#pragma acc parallel vector_length (vl) +#pragma acc loop reduction (||:lresult) + for (i = 0; i < n; i++) + lresult = lresult || (__real__(result) > __real__(array[i])); + + return 0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/sb-1.c b/gcc/testsuite/c-c++-common/goacc/sb-1.c new file mode 100644 index 0000000..5e55c95 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/sb-1.c @@ -0,0 +1,75 @@ +// { dg-skip-if "not yet" { c++ } } + +void foo() +{ + int l; + + bad1: + #pragma acc parallel + goto bad1; // { dg-error "invalid branch to/from OpenACC structured block" } + #pragma acc kernels + goto bad1; // { dg-error "invalid branch to/from OpenACC structured block" } + #pragma acc data + goto bad1; // { dg-error "invalid branch to/from OpenACC structured block" } + #pragma acc loop + for (l = 0; l < 2; ++l) + goto bad1; // { dg-error "invalid branch to/from OpenACC structured block" } + + goto bad2_parallel; // { dg-error "invalid entry to OpenACC structured block" } + #pragma acc parallel + { + bad2_parallel: ; + } + + goto bad2_kernels; // { dg-error "invalid entry to OpenACC structured block" } + #pragma acc kernels + { + bad2_kernels: ; + } + + goto bad2_data; // { dg-error "invalid entry to OpenACC structured block" } + #pragma acc data + { + bad2_data: ; + } + + goto bad2_loop; // { dg-error "invalid entry to OpenACC structured block" } + #pragma acc loop + for (l = 0; l < 2; ++l) + { + bad2_loop: ; + } + + #pragma acc parallel + { + int i; + goto ok1_parallel; + for (i = 0; i < 10; ++i) + { ok1_parallel: break; } + } + + #pragma acc kernels + { + int i; + goto ok1_kernels; + for (i = 0; i < 10; ++i) + { ok1_kernels: break; } + } + + #pragma acc data + { + int i; + goto ok1_data; + for (i = 0; i < 10; ++i) + { ok1_data: break; } + } + + #pragma acc loop + for (l = 0; l < 2; ++l) + { + int i; + goto ok1_loop; + for (i = 0; i < 10; ++i) + { ok1_loop: break; } + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/sb-2.c b/gcc/testsuite/c-c++-common/goacc/sb-2.c new file mode 100644 index 0000000..a6760ec --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/sb-2.c @@ -0,0 +1,22 @@ +// { dg-skip-if "not yet" { c++ } } + +void foo(int i) +{ + switch (i) // { dg-error "invalid entry to OpenACC structured block" } + { + #pragma acc parallel + { case 0:; } + } + + switch (i) // { dg-error "invalid entry to OpenACC structured block" } + { + #pragma acc kernels + { case 0:; } + } + + switch (i) // { dg-error "invalid entry to OpenACC structured block" } + { + #pragma acc data + { case 0:; } + } +} diff --git a/gcc/testsuite/c-c++-common/goacc/sb-3.c b/gcc/testsuite/c-c++-common/goacc/sb-3.c new file mode 100644 index 0000000..147b7b0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/sb-3.c @@ -0,0 +1,18 @@ +// { dg-skip-if "not yet" { c++ } } + +void f (void) +{ + int i, j; +#pragma acc loop + for(i = 1; i < 30; i++) + { + if (i == 7) goto out; // { dg-error "invalid branch to/from OpenACC structured block" } +#pragma acc loop // { dg-error "work-sharing region may not be closely nested inside of work-sharing, critical, ordered, master or explicit task region" } + for(j = 5; j < 10; j++) + { + if (i == 6 && j == 7) goto out; // { dg-error "invalid branch to/from OpenACC structured block" } + } + } + out: + ; +} diff --git a/gcc/testsuite/c-c++-common/goacc/update-1.c b/gcc/testsuite/c-c++-common/goacc/update-1.c new file mode 100644 index 0000000..97e9379 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/update-1.c @@ -0,0 +1,17 @@ +void +f (void) +{ +#pragma acc update /* { dg-error "'#pragma acc update' must contain at least one 'device' or 'host/self' clause" } */ + + int i = 0; + int a[10]; +#pragma acc update device(i) +#pragma acc update host(i) +#pragma acc update self(i) +#pragma acc update device(a[1:3]) +#pragma acc update host(a[1:3]) +#pragma acc update self(a[1:3]) +#pragma acc update device(a(1:3)) /* { dg-error "expected '\\\)' before '\\\(' token" } */ +#pragma acc update host(a(1:3)) /* { dg-error "expected '\\\)' before '\\\(' token" } */ +#pragma acc update self(a(1:3)) /* { dg-error "expected '\\\)' before '\\\(' token" } */ +} diff --git a/gcc/testsuite/g++.dg/goacc-gomp/goacc-gomp.exp b/gcc/testsuite/g++.dg/goacc-gomp/goacc-gomp.exp new file mode 100644 index 0000000..7e74d2b --- /dev/null +++ b/gcc/testsuite/g++.dg/goacc-gomp/goacc-gomp.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2006-2015 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/>. + +# Load support procs. +load_lib g++-dg.exp + +if { ![check_effective_target_fopenacc] \ + || ![check_effective_target_fopenmp] } { + return +} + +# Initialize `dg'. +dg-init + +# Main loop. +g++-dg-runtest [lsort [concat \ + [find $srcdir/$subdir *.C] \ + [find $srcdir/c-c++-common/goacc-gomp *.c]]] "" "-fopenacc -fopenmp" + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.dg/goacc/goacc.exp b/gcc/testsuite/g++.dg/goacc/goacc.exp new file mode 100644 index 0000000..0e96dfa --- /dev/null +++ b/gcc/testsuite/g++.dg/goacc/goacc.exp @@ -0,0 +1,35 @@ +# Copyright (C) 2006-2015 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/>. + +# Load support procs. +load_lib g++-dg.exp + +if ![check_effective_target_fopenacc] { + return +} + +# Initialize `dg'. +dg-init + +# Main loop. +g++-dg-runtest [lsort [concat \ + [find $srcdir/$subdir *.C] \ + [find $srcdir/c-c++-common/goacc *.c]]] "" "-fopenacc" + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.dg/gomp/block-1.C b/gcc/testsuite/g++.dg/gomp/block-1.C index 3ec6ac8..b0704ac 100644 --- a/gcc/testsuite/g++.dg/gomp/block-1.C +++ b/gcc/testsuite/g++.dg/gomp/block-1.C @@ -22,5 +22,5 @@ void foo() } } -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 7 } +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 7 } // { dg-message "error: invalid entry to OpenMP structured block" "" { target *-*-* } 9 } diff --git a/gcc/testsuite/g++.dg/gomp/block-2.C b/gcc/testsuite/g++.dg/gomp/block-2.C index 7d572c1..5336c5a 100644 --- a/gcc/testsuite/g++.dg/gomp/block-2.C +++ b/gcc/testsuite/g++.dg/gomp/block-2.C @@ -32,5 +32,5 @@ void foo() continue; } -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 14 } +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 14 } // { dg-message "error: invalid entry to OpenMP structured block" "" { target *-*-* } 16 } diff --git a/gcc/testsuite/g++.dg/gomp/block-3.C b/gcc/testsuite/g++.dg/gomp/block-3.C index 4b98d1c..23f9726 100644 --- a/gcc/testsuite/g++.dg/gomp/block-3.C +++ b/gcc/testsuite/g++.dg/gomp/block-3.C @@ -60,6 +60,6 @@ void foo() } } -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 21 } -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 26 } +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 21 } +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 26 } // { dg-message "error: invalid entry to OpenMP structured block" "" { target *-*-* } 31 } diff --git a/gcc/testsuite/g++.dg/gomp/block-5.C b/gcc/testsuite/g++.dg/gomp/block-5.C index 5023e37..d6d28c4 100644 --- a/gcc/testsuite/g++.dg/gomp/block-5.C +++ b/gcc/testsuite/g++.dg/gomp/block-5.C @@ -15,4 +15,4 @@ void foo() } } -// { dg-message "error: invalid branch to/from an OpenMP structured block" "" { target *-*-* } 7 } +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 7 } diff --git a/gcc/testsuite/g++.dg/gomp/target-1.C b/gcc/testsuite/g++.dg/gomp/target-1.C index ae23988..bcdac61 100644 --- a/gcc/testsuite/g++.dg/gomp/target-1.C +++ b/gcc/testsuite/g++.dg/gomp/target-1.C @@ -30,5 +30,5 @@ foo (int x) } } -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 } +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 } // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 } diff --git a/gcc/testsuite/g++.dg/gomp/target-2.C b/gcc/testsuite/g++.dg/gomp/target-2.C index 6bf8b18..273f8d5 100644 --- a/gcc/testsuite/g++.dg/gomp/target-2.C +++ b/gcc/testsuite/g++.dg/gomp/target-2.C @@ -30,5 +30,5 @@ foo (int x, int y) } } -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 } +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 } // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 } diff --git a/gcc/testsuite/g++.dg/gomp/taskgroup-1.C b/gcc/testsuite/g++.dg/gomp/taskgroup-1.C index c31aa61..e15d59d 100644 --- a/gcc/testsuite/g++.dg/gomp/taskgroup-1.C +++ b/gcc/testsuite/g++.dg/gomp/taskgroup-1.C @@ -30,5 +30,5 @@ foo (int x) } } -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 } +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 } // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 } diff --git a/gcc/testsuite/g++.dg/gomp/teams-1.C b/gcc/testsuite/g++.dg/gomp/teams-1.C index 86abe12..2b00bb6 100644 --- a/gcc/testsuite/g++.dg/gomp/teams-1.C +++ b/gcc/testsuite/g++.dg/gomp/teams-1.C @@ -64,7 +64,7 @@ bar (int x) } } -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 8 } +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 8 } // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 10 } -// { dg-error "invalid branch to/from an OpenMP structured block" "" { target *-*-* } 39 } +// { dg-error "invalid branch to/from OpenMP structured block" "" { target *-*-* } 39 } // { dg-error "invalid entry to OpenMP structured block" "" { target *-*-* } 41 } diff --git a/gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c b/gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c index 95e6b2d..6adabf4 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/jump-openmp.c @@ -11,7 +11,7 @@ void foo() { a[i] = b[i]; if (c == 5) - return; /* { dg-error "invalid branch to/from a Cilk Plus structured block" } */ + return; /* { dg-error "invalid branch to/from Cilk Plus structured block" } */ } } @@ -31,7 +31,7 @@ void baz() { bad1: #pragma omp parallel - goto bad1; /* { dg-error "invalid branch to/from an OpenMP structured block" } */ + goto bad1; /* { dg-error "invalid branch to/from OpenMP structured block" } */ goto bad2; /* { dg-error "invalid entry to OpenMP structured block" } */ #pragma omp parallel diff --git a/gcc/testsuite/gcc.dg/cilk-plus/jump.c b/gcc/testsuite/gcc.dg/cilk-plus/jump.c index 9ec3293..1ca886a 100644 --- a/gcc/testsuite/gcc.dg/cilk-plus/jump.c +++ b/gcc/testsuite/gcc.dg/cilk-plus/jump.c @@ -10,7 +10,7 @@ void foo() { a[i] = b[i]; if (c == 5) - return; /* { dg-error "invalid branch to.from a Cilk" } */ + return; /* { dg-error "invalid branch to/from Cilk Plus structured block" } */ } } @@ -23,5 +23,5 @@ void bar() a[i] = b[i]; } if (c == 6) - goto lab; /* { dg-error "invalid entry to Cilk Plus" } */ + goto lab; /* { dg-error "invalid entry to Cilk Plus structured block" } */ } diff --git a/gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp b/gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp new file mode 100644 index 0000000..50365bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/goacc-gomp/goacc-gomp.exp @@ -0,0 +1,38 @@ +# Copyright (C) 2006-2015 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/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp + +if { ![check_effective_target_fopenacc] \ + || ![check_effective_target_fopenmp] } { + return +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [concat \ + [find $srcdir/$subdir *.c] \ + [find $srcdir/c-c++-common/goacc-gomp *.c]]] "" "-fopenacc -fopenmp" + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.dg/goacc/acc_on_device-1.c b/gcc/testsuite/gcc.dg/goacc/acc_on_device-1.c new file mode 100644 index 0000000..1a0276e --- /dev/null +++ b/gcc/testsuite/gcc.dg/goacc/acc_on_device-1.c @@ -0,0 +1,20 @@ +/* Have to enable optimizations, as otherwise builtins won't be expanded. */ +/* { dg-additional-options "-O -fdump-rtl-expand -std=c89 -Wno-implicit-function-declaration" } */ + +int +f (void) +{ + int r = 0; + + r |= acc_on_device (); + r |= acc_on_device (1, 2); + r |= acc_on_device (3.14); + r |= acc_on_device ("hello"); + + return r; +} + +/* Unsuitable to be handled as a builtin, so we're expecting four calls. + { dg-final { scan-rtl-dump-times "\\\(call \[^\\n\]*\\\"acc_on_device" 4 "expand" } } */ + +/* { dg-final { cleanup-rtl-dump "expand" } } */ diff --git a/gcc/testsuite/gcc.dg/goacc/goacc.exp b/gcc/testsuite/gcc.dg/goacc/goacc.exp new file mode 100644 index 0000000..dd8c424 --- /dev/null +++ b/gcc/testsuite/gcc.dg/goacc/goacc.exp @@ -0,0 +1,37 @@ +# Copyright (C) 2006-2015 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/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp + +if ![check_effective_target_fopenacc] { + return +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [concat \ + [find $srcdir/$subdir *.c] \ + [find $srcdir/c-c++-common/goacc *.c]]] "" "-fopenacc" + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.dg/gomp/block-1.c b/gcc/testsuite/gcc.dg/gomp/block-1.c index dd7fe77..e67e6c3 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-1.c +++ b/gcc/testsuite/gcc.dg/gomp/block-1.c @@ -4,9 +4,9 @@ void foo() { bad1: #pragma omp parallel - goto bad1; // { dg-error "invalid branch" } + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } - goto bad2; // { dg-error "invalid entry" } + goto bad2; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp parallel { bad2: ; diff --git a/gcc/testsuite/gcc.dg/gomp/block-10.c b/gcc/testsuite/gcc.dg/gomp/block-10.c index 76ee397..69ae3c0 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-10.c +++ b/gcc/testsuite/gcc.dg/gomp/block-10.c @@ -3,28 +3,28 @@ void foo(int i) { int j; - switch (i) // { dg-error "invalid entry" } + switch (i) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp parallel { case 0:; } } - switch (i) // { dg-error "invalid entry" } + switch (i) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp for for (j = 0; j < 10; ++ j) { case 1:; } } - switch (i) // { dg-error "invalid entry" } + switch (i) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp critical { case 2:; } } - switch (i) // { dg-error "invalid entry" } + switch (i) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp master { case 3:; } } - switch (i) // { dg-error "invalid entry" } + switch (i) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp sections { case 4:; @@ -32,7 +32,7 @@ void foo(int i) { case 5:; } } } - switch (i) // { dg-error "invalid entry" } + switch (i) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp ordered { default:; } diff --git a/gcc/testsuite/gcc.dg/gomp/block-2.c b/gcc/testsuite/gcc.dg/gomp/block-2.c index 4c56add..5c01463 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-2.c +++ b/gcc/testsuite/gcc.dg/gomp/block-2.c @@ -11,9 +11,9 @@ void foo() bad1: #pragma omp for for (i = 0; i < 10; ++i) - goto bad1; // { dg-error "invalid branch" } + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } - goto bad2; // { dg-error "invalid entry" } + goto bad2; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp for for (i = 0; i < 10; ++i) { diff --git a/gcc/testsuite/gcc.dg/gomp/block-3.c b/gcc/testsuite/gcc.dg/gomp/block-3.c index b4530e9..0b21cb3 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-3.c +++ b/gcc/testsuite/gcc.dg/gomp/block-3.c @@ -9,7 +9,7 @@ void foo() { #pragma omp sections { - continue; // { dg-error "invalid branch" } + continue; // { dg-error "invalid branch to/from OpenMP structured block" } } } @@ -18,16 +18,16 @@ void foo() #pragma omp section { bad1: ; } #pragma omp section - goto bad1; // { dg-error "invalid branch" } + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } } #pragma omp sections { - goto bad2; // { dg-error "invalid branch" } + goto bad2; // { dg-error "invalid branch to/from OpenMP structured block" } } bad2:; - goto bad3; // { dg-error "invalid entry" } + goto bad3; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp sections { bad3: ; diff --git a/gcc/testsuite/gcc.dg/gomp/block-4.c b/gcc/testsuite/gcc.dg/gomp/block-4.c index 61f490c..b2ef9b1 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-4.c +++ b/gcc/testsuite/gcc.dg/gomp/block-4.c @@ -4,6 +4,6 @@ void foo() { #pragma omp critical { - return; // { dg-error "invalid branch" } + return; // { dg-error "invalid branch to/from OpenMP structured block" } } } diff --git a/gcc/testsuite/gcc.dg/gomp/block-5.c b/gcc/testsuite/gcc.dg/gomp/block-5.c index 741049f..7f3b37c 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-5.c +++ b/gcc/testsuite/gcc.dg/gomp/block-5.c @@ -4,12 +4,12 @@ void foo() { #pragma omp master { - goto bad1; // { dg-error "invalid branch" } + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } } #pragma omp master { bad1: - return; // { dg-error "invalid branch" } + return; // { dg-error "invalid branch to/from OpenMP structured block" } } } diff --git a/gcc/testsuite/gcc.dg/gomp/block-6.c b/gcc/testsuite/gcc.dg/gomp/block-6.c index 87e6392..fc9fdc8 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-6.c +++ b/gcc/testsuite/gcc.dg/gomp/block-6.c @@ -4,6 +4,6 @@ void foo() { #pragma omp ordered { - return; // { dg-error "invalid branch" } + return; // { dg-error "invalid branch to/from OpenMP structured block" } } } diff --git a/gcc/testsuite/gcc.dg/gomp/block-7.c b/gcc/testsuite/gcc.dg/gomp/block-7.c index 2bc1cdb..6219e7e 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-7.c +++ b/gcc/testsuite/gcc.dg/gomp/block-7.c @@ -6,15 +6,15 @@ void foo() for (i = 0; i < 10; ++i) { #pragma omp for - for (j = ({ continue; 0; }); // { dg-error "invalid branch" } - j < ({ continue; 10; }); // { dg-error "invalid branch" } - j += ({ continue; 1; })) // { dg-error "invalid branch" } + for (j = ({ continue; 0; }); // { dg-error "invalid branch to/from OpenMP structured block" } + j < ({ continue; 10; }); // { dg-error "invalid branch to/from OpenMP structured block" } + j += ({ continue; 1; })) // { dg-error "invalid branch to/from OpenMP structured block" } continue; #pragma omp for - for (j = ({ break; 0; }); // { dg-error "invalid branch" } - j < ({ break; 10; }); // { dg-error "invalid branch" } - j += ({ break; 1; })) // { dg-error "invalid branch" } + for (j = ({ break; 0; }); // { dg-error "invalid branch to/from OpenMP structured block" } + j < ({ break; 10; }); // { dg-error "invalid branch to/from OpenMP structured block" } + j += ({ break; 1; })) // { dg-error "invalid branch to/from OpenMP structured block" } break; // { dg-error "break" } } } diff --git a/gcc/testsuite/gcc.dg/gomp/block-8.c b/gcc/testsuite/gcc.dg/gomp/block-8.c index 3c717d9..f410070 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-8.c +++ b/gcc/testsuite/gcc.dg/gomp/block-8.c @@ -7,5 +7,5 @@ int foo() #pragma omp parallel for for (i = 0; i < 10; ++i) - return 0; // { dg-error "invalid branch" } + return 0; // { dg-error "invalid branch to/from OpenMP structured block" } } diff --git a/gcc/testsuite/gcc.dg/gomp/block-9.c b/gcc/testsuite/gcc.dg/gomp/block-9.c index 9217cb7..2fae3de 100644 --- a/gcc/testsuite/gcc.dg/gomp/block-9.c +++ b/gcc/testsuite/gcc.dg/gomp/block-9.c @@ -3,7 +3,7 @@ void foo(int i) { int j; - switch (i) // { dg-error "invalid entry" } + switch (i) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp parallel { case 0:; } diff --git a/gcc/testsuite/gcc.dg/gomp/target-1.c b/gcc/testsuite/gcc.dg/gomp/target-1.c index 09e65bd..aaa6a14 100644 --- a/gcc/testsuite/gcc.dg/gomp/target-1.c +++ b/gcc/testsuite/gcc.dg/gomp/target-1.c @@ -5,9 +5,9 @@ foo (int x) { bad1: #pragma omp target - goto bad1; /* { dg-error "invalid branch" } */ + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } - goto bad2; /* { dg-error "invalid entry" } */ + goto bad2; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp target { bad2: ; @@ -21,7 +21,7 @@ foo (int x) { ok1: break; } } - switch (x) /* { dg-error "invalid entry" } */ + switch (x) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp target { case 0:; } diff --git a/gcc/testsuite/gcc.dg/gomp/target-2.c b/gcc/testsuite/gcc.dg/gomp/target-2.c index 546a1d0..3a7afc4 100644 --- a/gcc/testsuite/gcc.dg/gomp/target-2.c +++ b/gcc/testsuite/gcc.dg/gomp/target-2.c @@ -5,9 +5,9 @@ foo (int x, int y) { bad1: #pragma omp target data map(tofrom: y) - goto bad1; /* { dg-error "invalid branch" } */ + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } - goto bad2; /* { dg-error "invalid entry" } */ + goto bad2; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp target data map(tofrom: y) { bad2: ; @@ -21,7 +21,7 @@ foo (int x, int y) { ok1: break; } } - switch (x) /* { dg-error "invalid entry" } */ + switch (x) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp target data map(tofrom: y) { case 0:; } diff --git a/gcc/testsuite/gcc.dg/gomp/taskgroup-1.c b/gcc/testsuite/gcc.dg/gomp/taskgroup-1.c index e301efc..1997e0c 100644 --- a/gcc/testsuite/gcc.dg/gomp/taskgroup-1.c +++ b/gcc/testsuite/gcc.dg/gomp/taskgroup-1.c @@ -5,9 +5,9 @@ foo (int x) { bad1: #pragma omp taskgroup - goto bad1; /* { dg-error "invalid branch" } */ + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } - goto bad2; /* { dg-error "invalid entry" } */ + goto bad2; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp taskgroup { bad2: ; @@ -21,7 +21,7 @@ foo (int x) { ok1: break; } } - switch (x) /* { dg-error "invalid entry" } */ + switch (x) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp taskgroup { case 0:; } diff --git a/gcc/testsuite/gcc.dg/gomp/teams-1.c b/gcc/testsuite/gcc.dg/gomp/teams-1.c index 73c00de..ad5b100 100644 --- a/gcc/testsuite/gcc.dg/gomp/teams-1.c +++ b/gcc/testsuite/gcc.dg/gomp/teams-1.c @@ -5,9 +5,9 @@ foo (int x) { bad1: #pragma omp target teams - goto bad1; /* { dg-error "invalid branch" } */ + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } - goto bad2; /* { dg-error "invalid entry" } */ + goto bad2; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp target teams { bad2: ; @@ -21,7 +21,7 @@ foo (int x) { ok1: break; } } - switch (x) /* { dg-error "invalid entry" } */ + switch (x) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp target teams { case 0:; } @@ -34,9 +34,9 @@ bar (int x) bad1: #pragma omp target #pragma omp teams - goto bad1; /* { dg-error "invalid branch" } */ + goto bad1; // { dg-error "invalid branch to/from OpenMP structured block" } - goto bad2; /* { dg-error "invalid entry" } */ + goto bad2; // { dg-error "invalid entry to OpenMP structured block" } #pragma omp target #pragma omp teams { @@ -52,7 +52,7 @@ bar (int x) { ok1: break; } } - switch (x) /* { dg-error "invalid entry" } */ + switch (x) // { dg-error "invalid entry to OpenMP structured block" } { #pragma omp target #pragma omp teams diff --git a/gcc/testsuite/gfortran.dg/goacc/acc_on_device-1.f95 b/gcc/testsuite/gfortran.dg/goacc/acc_on_device-1.f95 new file mode 100644 index 0000000..9dfde26 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/acc_on_device-1.f95 @@ -0,0 +1,22 @@ +! Have to enable optimizations, as otherwise builtins won't be expanded. +! { dg-additional-options "-O -fdump-rtl-expand" } + +logical function f () + implicit none + + external acc_on_device + logical (4) acc_on_device + + f = .false. + f = f .or. acc_on_device () + f = f .or. acc_on_device (1, 2) + f = f .or. acc_on_device (3.14) + f = f .or. acc_on_device ("hello") + + return +end function f + +! Unsuitable to be handled as a builtin, so we're expecting four calls. +! { dg-final { scan-rtl-dump-times "\\\(call \[^\\n\]*\\\"acc_on_device" 4 "expand" } } + +! { dg-final { cleanup-rtl-dump "expand" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/acc_on_device-2-off.f95 b/gcc/testsuite/gfortran.dg/goacc/acc_on_device-2-off.f95 new file mode 100644 index 0000000..cf28264 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/acc_on_device-2-off.f95 @@ -0,0 +1,39 @@ +! Have to enable optimizations, as otherwise builtins won't be expanded. +! { dg-additional-options "-O -fdump-rtl-expand -fno-openacc" } + +module openacc_kinds + implicit none + + integer, parameter :: acc_device_kind = 4 + +end module openacc_kinds + +module openacc + use openacc_kinds + implicit none + + integer (acc_device_kind), parameter :: acc_device_host = 2 + + interface + function acc_on_device (dev) + use openacc_kinds + logical (4) :: acc_on_device + integer (acc_device_kind), intent (in) :: dev + end function acc_on_device + end interface +end module openacc + +logical (4) function f () + use openacc + implicit none + + integer (4), parameter :: dev = 2 + + f = acc_on_device (dev) + return +end function f + +! Without -fopenacc, we're expecting one call. +! { dg-final { scan-rtl-dump-times "\\\(call \[^\\n\]*\\\"acc_on_device" 1 "expand" } } + +! { dg-final { cleanup-rtl-dump "expand" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/acc_on_device-2.f95 b/gcc/testsuite/gfortran.dg/goacc/acc_on_device-2.f95 new file mode 100644 index 0000000..7730a60 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/acc_on_device-2.f95 @@ -0,0 +1,40 @@ +! Have to enable optimizations, as otherwise builtins won't be expanded. +! { dg-additional-options "-O -fdump-rtl-expand" } + +module openacc_kinds + implicit none + + integer, parameter :: acc_device_kind = 4 + +end module openacc_kinds + +module openacc + use openacc_kinds + implicit none + + integer (acc_device_kind), parameter :: acc_device_host = 2 + + interface + function acc_on_device (dev) + use openacc_kinds + logical (4) :: acc_on_device + integer (acc_device_kind), intent (in) :: dev + end function acc_on_device + end interface +end module openacc + +logical (4) function f () + use openacc + implicit none + + integer (4), parameter :: dev = 2 + + f = acc_on_device (dev) + return +end function f + +! With -fopenacc, we're expecting the builtin to be expanded, so no calls. +! TODO: not working. +! { dg-final { scan-rtl-dump-times "\\\(call \[^\\n\]*\\\"acc_on_device" 0 "expand" { xfail *-*-* } } } + +! { dg-final { cleanup-rtl-dump "expand" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/assumed.f95 b/gcc/testsuite/gfortran.dg/goacc/assumed.f95 new file mode 100644 index 0000000..3287241 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/assumed.f95 @@ -0,0 +1,47 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +module test +contains + subroutine assumed_size(a) + implicit none + integer :: a(*), i + !$acc declare device_resident (a) ! { dg-error "Assumed size" } + !$acc data copy (a) ! { dg-error "Assumed size" } + !$acc end data + !$acc data deviceptr (a) ! { dg-error "Assumed size" } + !$acc end data + !$acc parallel private (a) ! { dg-error "Assumed size" } + !$acc end parallel + !$acc host_data use_device (a) ! { dg-error "Assumed size" } + !$acc end host_data + !$acc parallel loop reduction(+:a) ! { dg-error "Assumed size" } + do i = 1,5 + enddo + !$acc end parallel loop + !$acc update device (a) ! { dg-error "Assumed size" } + !$acc update host (a) ! { dg-error "Assumed size" } + !$acc update self (a) ! { dg-error "Assumed size" } + end subroutine assumed_size + subroutine assumed_rank(a) + implicit none + integer, intent(in) :: a(..) + integer :: i + !$acc declare device_resident (a) ! { dg-error "Assumed rank" } + !$acc data copy (a) ! { dg-error "Assumed rank" } + !$acc end data + !$acc data deviceptr (a) ! { dg-error "Assumed rank" } + !$acc end data + !$acc parallel private (a) ! { dg-error "Assumed rank" } + !$acc end parallel + !$acc host_data use_device (a) ! { dg-error "Assumed rank" } + !$acc end host_data + !$acc parallel loop reduction(+:a) ! { dg-error "Assumed rank" } + do i = 1,5 + enddo + !$acc end parallel loop + !$acc update device (a) ! { dg-error "Assumed rank" } + !$acc update host (a) ! { dg-error "Assumed rank" } + !$acc update self (a) ! { dg-error "Assumed rank" } + end subroutine assumed_rank +end module test diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 new file mode 100644 index 0000000..d630d38 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-1.f95 @@ -0,0 +1,91 @@ +! { dg-do compile } + +program asyncwait + integer, parameter :: N = 64 + real, allocatable :: a(:), b(:) + integer i + + allocate (a(N)) + allocate (b(N)) + + a(:) = 3.0 + b(:) = 0.0 + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1 2) ! { dg-error "Unclassifiable OpenACC directive" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,) ! { dg-error "Unclassifiable OpenACC directive" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (,1) ! { dg-error "Invalid character in name" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2,) ! { dg-error "Unclassifiable OpenACC directive" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2 3) ! { dg-error "Unclassifiable OpenACC directive" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1,2,,) ! { dg-error "Unclassifiable OpenACC directive" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1 ! { dg-error "Unclassifiable OpenACC directive" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (*) ! { dg-error "Invalid character in name at" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (a) ! { dg-error "ASYNC clause at \\\(1\\\) requires a scalar INTEGER expression" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (N) + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async (1.0) ! { dg-error "ASYNC clause at \\\(1\\\) requires a scalar INTEGER expression" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async () ! { dg-error "Invalid character in name at " } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) async + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel +end program asyncwait diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 new file mode 100644 index 0000000..db0ce1f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-2.f95 @@ -0,0 +1,91 @@ +! { dg-do compile } + +program asyncwait + integer, parameter :: N = 64 + real, allocatable :: a(:), b(:) + integer i + + allocate (a(N)) + allocate (b(N)) + + a(:) = 3.0 + b(:) = 0.0 + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (1 2) ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (1,) ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (,1) ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (1,2,) ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (1,2 3) ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (1,2,,) ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (1 ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (*) ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (a) ! { dg-error "WAIT clause at \\\(1\\\) requires a scalar INTEGER expression" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (N) + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait (1.0) ! { dg-error "WAIT clause at \\\(1\\\) requires a scalar INTEGER expression" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait () ! { dg-error "Syntax error in OpenACC expression list" } + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel ! { dg-error "Unexpected \\\!\\\$ACC END PARALLEL" } + + !$acc parallel copyin (a(1:N)) copy (b(1:N)) wait + do i = 1, N + b(i) = a(i) + end do + !$acc end parallel +end program asyncwait diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 new file mode 100644 index 0000000..32c11de --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-3.f95 @@ -0,0 +1,41 @@ +! { dg-do compile } + +program asyncwait + integer, parameter :: N = 64 + real, allocatable :: a(:), b(:) + integer i + + allocate (a(N)) + allocate (b(N)) + + a(:) = 3.0 + b(:) = 0.0 + + !$acc wait (1 2) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait (1,) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait (,1) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait (1, 2, ) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait (1, 2, ,) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait (1 ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait (1, *) ! { dg-error "Invalid argument to \\\$\\\!ACC WAIT" } + + !$acc wait (1, a) ! { dg-error "WAIT clause at \\\(1\\\) requires a scalar INTEGER expression" } + + !$acc wait (a) ! { dg-error "WAIT clause at \\\(1\\\) requires a scalar INTEGER expression" } + + !$acc wait (N) + + !$acc wait (1.0) ! { dg-error "WAIT clause at \\\(1\\\) requires a scalar INTEGER expression" } + + !$acc wait 1 ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait N ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait (1) +end program asyncwait diff --git a/gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 b/gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 new file mode 100644 index 0000000..cd64ef3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/asyncwait-4.f95 @@ -0,0 +1,37 @@ +! { dg-do compile } + +program asyncwait + integer, parameter :: N = 64 + real, allocatable :: a(:), b(:) + integer i + + allocate (a(N)) + allocate (b(N)) + + a(:) = 3.0 + b(:) = 0.0 + + !$acc wait async (1 2) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (1,) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (,1) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (1, 2, ) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (1, 2, ,) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (1 ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (1, *) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (1, a) ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } + + !$acc wait async (a) ! { dg-error "ASYNC clause at \\\(1\\\) requires a scalar INTEGER expression" } + + !$acc wait async (N) + + !$acc wait async (1.0) ! { dg-error "ASYNC clause at \\\(1\\\) requires a scalar INTEGER expression" } + + !$acc wait async 1 ! { dg-error "Unexpected junk in \\\!\\\$ACC WAIT at" } +end program asyncwait diff --git a/gcc/testsuite/gfortran.dg/goacc/branch.f95 b/gcc/testsuite/gfortran.dg/goacc/branch.f95 new file mode 100644 index 0000000..7eed3e2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/branch.f95 @@ -0,0 +1,53 @@ +! { dg-do compile } + +program test + implicit none + + integer :: i + + if (.true.) then + !$acc parallel + end if ! { dg-error "Unexpected" } + !$acc end parallel + end if + + if (.true.) then + !$acc kernels + end if ! { dg-error "Unexpected" } + !$acc end kernels + end if + + !$acc parallel + if (.true.) then + !$acc end parallel ! { dg-error "Unexpected" } + end if + !$acc end parallel + + !$acc kernels + if (.true.) then + !$acc end kernels ! { dg-error "Unexpected" } + end if + !$acc end kernels + + !$acc parallel + if (.true.) then + end if + !$acc end parallel + + !$acc kernels + if (.true.) then + end if + !$acc end kernels + + if (.true.) then + !$acc parallel + !$acc end parallel + end if + + if (.true.) then + !$acc kernels + !$acc end kernels + end if + + +end program test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/cache-1.f95 b/gcc/testsuite/gfortran.dg/goacc/cache-1.f95 new file mode 100644 index 0000000..746cf02 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/cache-1.f95 @@ -0,0 +1,12 @@ +! { dg-do compile } +! { dg-additional-options "-std=f2008" } + +program test + implicit none + integer :: i, d(10) + + do concurrent (i=1:5) + !$acc cache (d) + enddo +end +! { dg-prune-output "unimplemented" } diff --git a/gcc/testsuite/gfortran.dg/goacc/coarray.f95 b/gcc/testsuite/gfortran.dg/goacc/coarray.f95 new file mode 100644 index 0000000..4f1224e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/coarray.f95 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-additional-options "-fcoarray=single" } + +! TODO: These cases must fail + +module test +contains + subroutine oacc1(a) + implicit none + integer :: i + integer, codimension[*] :: a + !$acc declare device_resident (a) + !$acc data copy (a) + !$acc end data + !$acc data deviceptr (a) + !$acc end data + !$acc parallel private (a) + !$acc end parallel + !$acc host_data use_device (a) + !$acc end host_data + !$acc parallel loop reduction(+:a) + do i = 1,5 + enddo + !$acc end parallel loop + !$acc parallel loop + do i = 1,5 + !$acc cache (a) + enddo + !$acc end parallel loop + !$acc update device (a) + !$acc update host (a) + !$acc update self (a) + end subroutine oacc1 +end module test +! { dg-prune-output "ACC cache unimplemented" } diff --git a/gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f95 b/gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f95 new file mode 100644 index 0000000..1c9a3f3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/continuation-free-form.f95 @@ -0,0 +1,23 @@ +! { dg-do compile } + +program test + implicit none + + integer :: i + real :: x + + !$acc parallel & + !$acc loop & ! continuation + !$acc & reduction(+:x) + + ! this line must be ignored + !$acc ! kernels + do i = 1,10 + x = x + 0.3 + enddo + ! continuation must begin with sentinel + !$acc end parallel & ! { dg-error "Unclassifiable OpenACC directive" } + ! loop + + print *, x +end
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/cray.f95 b/gcc/testsuite/gfortran.dg/goacc/cray.f95 new file mode 100644 index 0000000..8f2c077 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/cray.f95 @@ -0,0 +1,56 @@ +! { dg-do compile } +! { dg-additional-options "-fcray-pointer" } + +module test +contains + subroutine oacc1 + implicit none + integer :: i + real :: pointee + pointer (ptr, pointee) + !$acc declare device_resident (pointee) + !$acc declare device_resident (ptr) + !$acc data copy (pointee) ! { dg-error "Cray pointee" } + !$acc end data + !$acc data deviceptr (pointee) ! { dg-error "Cray pointee" } + !$acc end data + !$acc parallel private (pointee) ! { dg-error "Cray pointee" } + !$acc end parallel + !$acc host_data use_device (pointee) ! { dg-error "Cray pointee" } + !$acc end host_data + !$acc parallel loop reduction(+:pointee) ! { dg-error "Cray pointee" } + do i = 1,5 + enddo + !$acc end parallel loop + !$acc parallel loop + do i = 1,5 + ! Subarrays are not implemented yet + !$acc cache (pointee) ! TODO: This must fail, as in openacc-1_0-branch + enddo + !$acc end parallel loop + !$acc update device (pointee) ! { dg-error "Cray pointee" } + !$acc update host (pointee) ! { dg-error "Cray pointee" } + !$acc update self (pointee) ! { dg-error "Cray pointee" } + !$acc data copy (ptr) + !$acc end data + !$acc data deviceptr (ptr) ! { dg-error "Cray pointer" } + !$acc end data + !$acc parallel private (ptr) + !$acc end parallel + !$acc host_data use_device (ptr) ! { dg-error "Cray pointer" } + !$acc end host_data + !$acc parallel loop reduction(+:ptr) ! { dg-error "Cray pointer" } + do i = 1,5 + enddo + !$acc end parallel loop + !$acc parallel loop + do i = 1,5 + !$acc cache (ptr) ! TODO: This must fail, as in openacc-1_0-branch + enddo + !$acc end parallel loop + !$acc update device (ptr) + !$acc update host (ptr) + !$acc update self (ptr) + end subroutine oacc1 +end module test +! { dg-prune-output "unimplemented" } diff --git a/gcc/testsuite/gfortran.dg/goacc/critical.f95 b/gcc/testsuite/gfortran.dg/goacc/critical.f95 new file mode 100644 index 0000000..510ea18 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/critical.f95 @@ -0,0 +1,27 @@ +! { dg-do compile } +! { dg-additional-options "-fcoarray=single" } + +module test +contains + subroutine oacc1 + implicit none + integer :: i, j + j = 0 + !$acc parallel + critical ! { dg-error "CRITICAL block inside of" } + j = j + 1 + end critical + !$acc end parallel + end subroutine oacc1 + + subroutine oacc2 + implicit none + integer :: i, j + j = 0 + critical + !$acc parallel ! { dg-error "OpenACC directive inside of" } + j = j + 1 + !$acc end parallel + end critical + end subroutine oacc2 +end module test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/data-clauses.f95 b/gcc/testsuite/gfortran.dg/goacc/data-clauses.f95 new file mode 100644 index 0000000..b94214e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/data-clauses.f95 @@ -0,0 +1,259 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +module test + implicit none +contains + + subroutine foo (vi, asa) + integer, value :: vi + integer :: i, ia(10) + complex :: c, ca(10) + real, target:: r + real :: ra(10) + real, pointer :: rp + real, dimension(:), allocatable :: aa + real, dimension(:) :: asa + type t + integer :: i + end type + type(t) :: ti + type(t), allocatable :: tia + type(t), target :: tit + type(t), pointer :: tip + rp => r + tip => tit + + !$acc parallel deviceptr (rp) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel deviceptr (vi) ! { dg-error "VALUE" } + !$acc end parallel + !$acc parallel deviceptr (aa) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + + !$acc parallel deviceptr (i, c, r, ia, ca, ra, asa, ti) + !$acc end parallel + !$acc kernels deviceptr (i, c, r, ia, ca, ra, asa, ti) + !$acc end kernels + !$acc data deviceptr (i, c, r, ia, ca, ra, asa, ti) + !$acc end data + + + !$acc parallel copy (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel copy (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) copy (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel copy (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels copy (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data copy (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel copyin (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel copyin (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel copyin (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels copyin (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data copyin (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel copyout (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel copyout (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyin (i) copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel copyout (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels copyout (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data copyout (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel create (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel create (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyin (i) create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyout (i) create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel create (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels create (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data create (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel present (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel present (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) present (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) present (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyin (i) present (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyout (i) present (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel create (i) present (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel present (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels present (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data present (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel pcopy (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc parallel pcopyin (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc parallel pcopyout (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc parallel pcreate (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + + + !$acc parallel present_or_copy (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel present_or_copy (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) present_or_copy (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) present_or_copy (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyin (i) present_or_copy (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyout (i) present_or_copy (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel create (i) present_or_copy (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present (i) present_or_copy (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel present_or_copy (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels present_or_copy (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data present_or_copy (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel present_or_copyin (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel present_or_copyin (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyin (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyout (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel create (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present_or_copy (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel present_or_copyin (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels present_or_copyin (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data present_or_copyin (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel present_or_copyout (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel present_or_copyout (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyin (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyout (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel create (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present_or_copy (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present_or_copyin (i) present_or_copyout (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel present_or_copyout (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels present_or_copyout (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data present_or_copyout (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + + !$acc parallel present_or_create (tip) ! { dg-error "POINTER" } + !$acc end parallel + !$acc parallel present_or_create (tia) ! { dg-error "ALLOCATABLE" } + !$acc end parallel + !$acc parallel deviceptr (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copy (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyin (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel copyout (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel create (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present_or_copy (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present_or_copyin (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + !$acc parallel present_or_copyout (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc end parallel + + !$acc parallel present_or_create (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end parallel + !$acc kernels present_or_create (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end kernels + !$acc data present_or_create (i, c, r, ia, ca, ra, asa, rp, ti, vi, aa) + !$acc end data + + end subroutine foo +end module test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/data-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/data-tree.f95 new file mode 100644 index 0000000..32c50fd --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/data-tree.f95 @@ -0,0 +1,30 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } + +program test + implicit none + integer :: q, i, j, k, m, n, o, p, r, s, t, u, v, w + logical :: l + + !$acc data if(l) copy(i), copyin(j), copyout(k), create(m) & + !$acc present(o), pcopy(p), pcopyin(r), pcopyout(s), pcreate(t) & + !$acc deviceptr(u) + !$acc end data + +end program test +! { dg-final { scan-tree-dump-times "pragma acc data" 1 "original" } } + +! { dg-final { scan-tree-dump-times "if" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_tofrom:i\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_to:j\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_from:k\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_alloc:m\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "map\\(force_present:o\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(tofrom:p\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(to:r\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(from:s\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(alloc:t\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "map\\(force_deviceptr:u\\)" 1 "original" } } +! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/declare-1.f95 b/gcc/testsuite/gfortran.dg/goacc/declare-1.f95 new file mode 100644 index 0000000..03540f1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/declare-1.f95 @@ -0,0 +1,20 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } + +program test + implicit none + integer :: i + + !$acc declare copy(i) +contains + real function foo(n) + integer, value :: n + BLOCK + integer i + !$acc declare copy(i) + END BLOCK + end function foo +end program test +! { dg-prune-output "unimplemented" } +! { dg-final { scan-tree-dump-times "pragma acc declare map\\(force_tofrom:i\\)" 2 "original" } } +! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 b/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 new file mode 100644 index 0000000..8f1715e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 @@ -0,0 +1,88 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +module test + implicit none +contains + + subroutine foo (vi) + logical :: l + integer, value :: vi + integer :: i, ia(10), a(10), b(2:8) + complex :: c, ca(10) + real, target:: r + real :: ra(10) + real, pointer :: rp + real, dimension(:), allocatable :: aa + type t + integer :: i + end type + type(t) :: ti + type(t), allocatable :: tia + type(t), target :: tit + type(t), pointer :: tip + rp => r + tip => tit + + ! enter data + !$acc enter data + !$acc enter data if (.false.) + !$acc enter data if (l) + !$acc enter data if (.false.) if (l) ! { dg-error "Unclassifiable" } + !$acc enter data if (i) ! { dg-error "LOGICAL" } + !$acc enter data if (1) ! { dg-error "LOGICAL" } + !$acc enter data if (a) ! { dg-error "LOGICAL" } + !$acc enter data if (b(5:6)) ! { dg-error "LOGICAL" } + !$acc enter data async (l) ! { dg-error "INTEGER" } + !$acc enter data async (.true.) ! { dg-error "INTEGER" } + !$acc enter data async (1) + !$acc enter data async (i) + !$acc enter data async (a) ! { dg-error "INTEGER" } + !$acc enter data async (b(5:6)) ! { dg-error "INTEGER" } + !$acc enter data wait (l) ! { dg-error "INTEGER" } + !$acc enter data wait (.true.) ! { dg-error "INTEGER" } + !$acc enter data wait (i, 1) + !$acc enter data wait (a) ! { dg-error "INTEGER" } + !$acc enter data wait (b(5:6)) ! { dg-error "INTEGER" } + !$acc enter data copyin (tip) ! { dg-error "POINTER" } + !$acc enter data copyin (tia) ! { dg-error "ALLOCATABLE" } + !$acc enter data create (tip) ! { dg-error "POINTER" } + !$acc enter data create (tia) ! { dg-error "ALLOCATABLE" } + !$acc enter data present_or_copyin (tip) ! { dg-error "POINTER" } + !$acc enter data present_or_copyin (tia) ! { dg-error "ALLOCATABLE" } + !$acc enter data present_or_create (tip) ! { dg-error "POINTER" } + !$acc enter data present_or_create (tia) ! { dg-error "ALLOCATABLE" } + !$acc enter data copyin (i) create (i) ! { dg-error "multiple clauses" } + !$acc enter data copyin (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc enter data create (i) present_or_copyin (i) ! { dg-error "multiple clauses" } + !$acc enter data copyin (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc enter data create (i) present_or_create (i) ! { dg-error "multiple clauses" } + !$acc enter data present_or_copyin (i) present_or_create (i) ! { dg-error "multiple clauses" } + + ! exit data + !$acc exit data + !$acc exit data if (.false.) + !$acc exit data if (l) + !$acc exit data if (.false.) if (l) ! { dg-error "Unclassifiable" } + !$acc exit data if (i) ! { dg-error "LOGICAL" } + !$acc exit data if (1) ! { dg-error "LOGICAL" } + !$acc exit data if (a) ! { dg-error "LOGICAL" } + !$acc exit data if (b(5:6)) ! { dg-error "LOGICAL" } + !$acc exit data async (l) ! { dg-error "INTEGER" } + !$acc exit data async (.true.) ! { dg-error "INTEGER" } + !$acc exit data async (1) + !$acc exit data async (i) + !$acc exit data async (a) ! { dg-error "INTEGER" } + !$acc exit data async (b(5:6)) ! { dg-error "INTEGER" } + !$acc exit data wait (l) ! { dg-error "INTEGER" } + !$acc exit data wait (.true.) ! { dg-error "INTEGER" } + !$acc exit data wait (i, 1) + !$acc exit data wait (a) ! { dg-error "INTEGER" } + !$acc exit data wait (b(5:6)) ! { dg-error "INTEGER" } + !$acc exit data copyout (tip) ! { dg-error "POINTER" } + !$acc exit data copyout (tia) ! { dg-error "ALLOCATABLE" } + !$acc exit data delete (tip) ! { dg-error "POINTER" } + !$acc exit data delete (tia) ! { dg-error "ALLOCATABLE" } + !$acc exit data copyout (i) delete (i) ! { dg-error "multiple clauses" } + end subroutine foo +end module test diff --git a/gcc/testsuite/gfortran.dg/goacc/fixed-1.f b/gcc/testsuite/gfortran.dg/goacc/fixed-1.f new file mode 100644 index 0000000..6a454190 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/fixed-1.f @@ -0,0 +1,12 @@ + INTEGER :: ARGC + ARGC = COMMAND_ARGUMENT_COUNT () + +!$OMP PARALLEL +!$ACC PARALLEL COPYIN(ARGC) + IF (ARGC .NE. 0) THEN + CALL ABORT + END IF +!$ACC END PARALLEL +!$OMP END PARALLEL + + END diff --git a/gcc/testsuite/gfortran.dg/goacc/fixed-2.f b/gcc/testsuite/gfortran.dg/goacc/fixed-2.f new file mode 100644 index 0000000..2c2b0a3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/fixed-2.f @@ -0,0 +1,15 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + + INTEGER :: ARGC + ARGC = COMMAND_ARGUMENT_COUNT () + +!$OMP xPARALLEL +!$ACC xPARALLEL COPYIN(ARGC) ! { dg-error "Unclassifiable OpenACC directive" } + IF (ARGC .NE. 0) THEN + CALL ABORT + END IF +!$ACC END PARALLEL ! { dg-error "Unexpected" } +!$OMP END PARALLEL + + END diff --git a/gcc/testsuite/gfortran.dg/goacc/fixed-3.f b/gcc/testsuite/gfortran.dg/goacc/fixed-3.f new file mode 100644 index 0000000..ede361e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/fixed-3.f @@ -0,0 +1,13 @@ + IMPLICIT NONE + + INTEGER DEV + +!$ACC PARALLEL + DEV = 0 +!$ACC END PARALLEL + +!$ACC PARALLEL + DEV = 0 +!$ACC END PARALLEL + + END diff --git a/gcc/testsuite/gfortran.dg/goacc/fixed-4.f b/gcc/testsuite/gfortran.dg/goacc/fixed-4.f new file mode 100644 index 0000000..120d5a9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/fixed-4.f @@ -0,0 +1,6 @@ + IMPLICIT NONE + +!$ACC PARALLEL +!$ACC END PARALLEL + + END diff --git a/gcc/testsuite/gfortran.dg/goacc/goacc.exp b/gcc/testsuite/gfortran.dg/goacc/goacc.exp new file mode 100644 index 0000000..dcacb31 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/goacc.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2005-2015 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/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gfortran-dg.exp + +if ![check_effective_target_fopenacc] { + return +} + +# Initialize `dg'. +dg-init + +# Main loop. +gfortran-dg-runtest [lsort \ + [find $srcdir/$subdir *.\[fF\]{,90,95,03,08} ] ] "" "-fopenacc" + +# All done. +dg-finish diff --git a/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 new file mode 100644 index 0000000..19e7411 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 @@ -0,0 +1,13 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } + +program test + implicit none + integer :: i + + !$acc host_data use_device(i) + !$acc end host_data +end program test +! { dg-prune-output "unimplemented" } +! { dg-final { scan-tree-dump-times "pragma acc host_data use_device\\(i\\)" 1 "original" } } +! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/if.f95 b/gcc/testsuite/gfortran.dg/goacc/if.f95 new file mode 100644 index 0000000..a45035d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/if.f95 @@ -0,0 +1,52 @@ +! { dg-do compile } + +program test + implicit none + + logical :: x + integer :: i + + !$acc parallel if ! { dg-error "Unclassifiable OpenACC directive" } + !$acc parallel if () ! { dg-error "Invalid character" } + !$acc parallel if (i) ! { dg-error "scalar LOGICAL expression" } + !$acc end parallel + !$acc parallel if (1) ! { dg-error "scalar LOGICAL expression" } + !$acc end parallel + !$acc kernels if (i) ! { dg-error "scalar LOGICAL expression" } + !$acc end kernels + !$acc kernels if ! { dg-error "Unclassifiable OpenACC directive" } + !$acc kernels if () ! { dg-error "Invalid character" } + !$acc kernels if (1) ! { dg-error "scalar LOGICAL expression" } + !$acc end kernels + !$acc data if ! { dg-error "Unclassifiable OpenACC directive" } + !$acc data if () ! { dg-error "Invalid character" } + !$acc data if (i) ! { dg-error "scalar LOGICAL expression" } + !$acc end data + !$acc data if (1) ! { dg-error "scalar LOGICAL expression" } + !$acc end data + + ! at most one if clause may appear + !$acc parallel if (.false.) if (.false.) { dg-error "Unclassifiable OpenACC directive" } + !$acc kernels if (.false.) if (.false.) { dg-error "Unclassifiable OpenACC directive" } + !$acc data if (.false.) if (.false.) { dg-error "Unclassifiable OpenACC directive" } + + !$acc parallel if (x) + !$acc end parallel + !$acc parallel if (.true.) + !$acc end parallel + !$acc parallel if (i.gt.1) + !$acc end parallel + !$acc kernels if (x) + !$acc end kernels + !$acc kernels if (.true.) + !$acc end kernels + !$acc kernels if (i.gt.1) + !$acc end kernels + !$acc data if (x) + !$acc end data + !$acc data if (.true.) + !$acc end data + !$acc data if (i.gt.1) + !$acc end data + +end program test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 new file mode 100644 index 0000000..7585a16 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 @@ -0,0 +1,32 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } + +program test + implicit none + integer :: q, i, j, k, m, n, o, p, r, s, t, u, v, w + logical :: l + + !$acc kernels if(l) async copy(i), copyin(j), copyout(k), create(m) & + !$acc present(o), pcopy(p), pcopyin(r), pcopyout(s), pcreate(t) & + !$acc deviceptr(u) + !$acc end kernels + +end program test +! { dg-final { scan-tree-dump-times "pragma acc kernels" 1 "original" } } + +! { dg-final { scan-tree-dump-times "if" 1 "original" } } +! { dg-final { scan-tree-dump-times "async" 1 "original" } } + +! { dg-final { scan-tree-dump-times "map\\(force_tofrom:i\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_to:j\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_from:k\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_alloc:m\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "map\\(force_present:o\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(tofrom:p\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(to:r\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(from:s\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(alloc:t\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "map\\(force_deviceptr:u\\)" 1 "original" } } +! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/list.f95 b/gcc/testsuite/gfortran.dg/goacc/list.f95 new file mode 100644 index 0000000..94fdadd --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/list.f95 @@ -0,0 +1,111 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +program test + implicit none + + integer :: i, j, k, l, a(10) + common /b/ j, k + real, pointer :: p1 => NULL() + complex :: c, d(10) + + !$acc parallel private(i) + !$acc end parallel + + !$acc parallel private(a) + !$acc end parallel + + !$acc parallel private(c, d) + !$acc end parallel + + !$acc parallel private(i, j, k, l, a) + !$acc end parallel + + !$acc parallel private (i) private (j) + !$acc end parallel + + !$acc parallel private ! { dg-error "Unclassifiable OpenACC directive" } + + !$acc parallel private() ! { dg-error "Syntax error" } + + !$acc parallel private(a(1:3)) ! { dg-error "Syntax error" } + + !$acc parallel private(10) ! { dg-error "Syntax error" } + + !$acc parallel private(/b/, /b/) ! { dg-error "present on multiple clauses" } + !$acc end parallel + + !$acc parallel private(i, j, i) ! { dg-error "present on multiple clauses" } + !$acc end parallel + + !$acc parallel private(p1) + !$acc end parallel + + !$acc parallel firstprivate(i) + !$acc end parallel + + !$acc parallel firstprivate(c, d) + !$acc end parallel + + !$acc parallel firstprivate(a) + !$acc end parallel + + !$acc parallel firstprivate(i, j, k, l, a) + !$acc end parallel + + !$acc parallel firstprivate (i) firstprivate (j) + !$acc end parallel + + !$acc parallel firstprivate ! { dg-error "Unclassifiable OpenACC directive" } + + !$acc parallel firstprivate() ! { dg-error "Syntax error" } + + !$acc parallel firstprivate(a(1:3)) ! { dg-error "Syntax error" } + + !$acc parallel firstprivate(10) ! { dg-error "Syntax error" } + + !$acc parallel firstprivate (/b/, /b/) ! { dg-error "present on multiple clauses" } + !$acc end parallel + + !$acc parallel firstprivate (i, j, i) ! { dg-error "present on multiple clauses" } + !$acc end parallel + + !$acc parallel firstprivate(p1) + !$acc end parallel + + !$acc parallel private (i) firstprivate (i) ! { dg-error "present on multiple clauses" } + !$acc end parallel + + !$acc host_data use_device(i) + !$acc end host_data + + !$acc host_data use_device(c, d) + !$acc end host_data + + !$acc host_data use_device(a) + !$acc end host_data + + !$acc host_data use_device(i, j, k, l, a) + !$acc end host_data + + !$acc host_data use_device (i) use_device (j) + !$acc end host_data + + !$acc host_data use_device ! { dg-error "Unclassifiable OpenACC directive" } + + !$acc host_data use_device() ! { dg-error "Syntax error" } + + !$acc host_data use_device(a(1:3)) ! { dg-error "Syntax error" } + + !$acc host_data use_device(10) ! { dg-error "Syntax error" } + + !$acc host_data use_device(/b/, /b/) ! { dg-error "present on multiple clauses" } + !$acc end host_data + + !$acc host_data use_device(i, j, i) ! { dg-error "present on multiple clauses" } + !$acc end host_data + + !$acc host_data use_device(p1) ! { dg-error "POINTER" } + !$acc end host_data + +end program test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/literal.f95 b/gcc/testsuite/gfortran.dg/goacc/literal.f95 new file mode 100644 index 0000000..e6760d0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/literal.f95 @@ -0,0 +1,30 @@ +! { dg-do compile } + +module test +contains + subroutine oacc1 + implicit none + integer :: i + !$acc declare device_resident (10) ! { dg-error "Syntax error" } + !$acc data copy (10) ! { dg-error "Syntax error" } + !$acc end data ! { dg-error "Unexpected" } + !$acc data deviceptr (10) ! { dg-error "Syntax error" } + !$acc end data ! { dg-error "Unexpected" } + !$acc data private (10) ! { dg-error "Unclassifiable" } + !$acc end data ! { dg-error "Unexpected" } + !$acc host_data use_device (10) ! { dg-error "Syntax error" } + !$acc end host_data ! { dg-error "Unexpected" } + !$acc parallel loop reduction(+:10) ! { dg-error "Syntax error" } + do i = 1,5 + enddo + !$acc end parallel loop ! { dg-error "Unexpected" } + !$acc parallel loop + do i = 1,5 + !$acc cache (10) ! { dg-error "Syntax error" } + enddo + !$acc end parallel loop + !$acc update device (10) ! { dg-error "Syntax error" } + !$acc update host (10) ! { dg-error "Syntax error" } + !$acc update self (10) ! { dg-error "Syntax error" } + end subroutine oacc1 +end module test diff --git a/gcc/testsuite/gfortran.dg/goacc/loop-1.f95 b/gcc/testsuite/gfortran.dg/goacc/loop-1.f95 new file mode 100644 index 0000000..e1b2dfd --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/loop-1.f95 @@ -0,0 +1,171 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } +module test + implicit none +contains + +subroutine test1 + integer :: i, j, k, b(10) + integer, dimension (30) :: a + double precision :: d + real :: r + i = 0 + !$acc loop + do 100 ! { dg-error "cannot be a DO WHILE or DO without loop control" } + if (i .gt. 0) exit ! { dg-error "EXIT statement" } + 100 i = i + 1 + i = 0 + !$acc loop + do ! { dg-error "cannot be a DO WHILE or DO without loop control" } + if (i .gt. 0) exit ! { dg-error "EXIT statement" } + i = i + 1 + end do + i = 0 + !$acc loop + do 200 while (i .lt. 4) ! { dg-error "cannot be a DO WHILE or DO without loop control" } + 200 i = i + 1 + !$acc loop + do while (i .lt. 8) ! { dg-error "cannot be a DO WHILE or DO without loop control" } + i = i + 1 + end do + !$acc loop + do 300 d = 1, 30, 6 ! { dg-error "integer" } + i = d + 300 a(i) = 1 + !$acc loop + do d = 1, 30, 5 ! { dg-error "integer" } + i = d + a(i) = 2 + end do + !$acc loop + do i = 1, 30 + if (i .eq. 16) exit ! { dg-error "EXIT statement" } + end do + !$acc loop + outer: do i = 1, 30 + do j = 5, 10 + if (i .eq. 6 .and. j .eq. 7) exit outer ! { dg-error "EXIT statement" } + end do + end do outer + last: do i = 1, 30 + end do last + + ! different types of loop are allowed + !$acc loop + do i = 1,10 + end do + !$acc loop + do 400, i = 1,10 +400 a(i) = i + + ! after loop directive must be loop + !$acc loop + a(1) = 1 ! { dg-error "Expected DO loop" } + do i = 1,10 + enddo + + ! combined directives may be used with/without end + !$acc parallel loop + do i = 1,10 + enddo + !$acc parallel loop + do i = 1,10 + enddo + !$acc end parallel loop + !$acc kernels loop + do i = 1,10 + enddo + !$acc kernels loop + do i = 1,10 + enddo + !$acc end kernels loop + + !$acc kernels loop reduction(max:i) + do i = 1,10 + enddo + !$acc kernels + !$acc loop reduction(max:i) + do i = 1,10 + enddo + !$acc end kernels + + !$acc parallel loop collapse(0) ! { dg-error "constant positive integer" } + do i = 1,10 + enddo + + !$acc parallel loop collapse(-1) ! { dg-error "constant positive integer" } + do i = 1,10 + enddo + + !$acc parallel loop collapse(i) ! { dg-error "Constant expression required" } + do i = 1,10 + enddo + + !$acc parallel loop collapse(4) ! { dg-error "not enough DO loops for collapsed" } + do i = 1, 3 + do j = 4, 6 + do k = 5, 7 + a(i+j-k) = i + j + k + end do + end do + end do + !$acc parallel loop collapse(2) + do i = 1, 5, 2 + do j = i + 1, 7, i ! { dg-error "collapsed loops don.t form rectangular iteration space" } + end do + end do + !$acc parallel loop collapse(2) + do i = 1, 3 + do j = 4, 6 + end do + end do + !$acc parallel loop collapse(2) + do i = 1, 3 + do j = 4, 6 + end do + k = 4 + end do + !$acc parallel loop collapse(3-1) + do i = 1, 3 + do j = 4, 6 + end do + k = 4 + end do + !$acc parallel loop collapse(1+1) + do i = 1, 3 + do j = 4, 6 + end do + k = 4 + end do + !$acc parallel loop collapse(2) + do i = 1, 3 + do ! { dg-error "cannot be a DO WHILE or DO without loop control" } + end do + end do + !$acc parallel loop collapse(2) + do i = 1, 3 + do r = 4, 6 ! { dg-error "integer" } + end do + end do + + ! Both seq and independent are not allowed + !$acc loop independent seq ! { dg-error "SEQ conflicts with INDEPENDENT" } + do i = 1,10 + enddo + + + !$acc cache (a) ! { dg-error "inside of loop" } + + do i = 1,10 + !$acc cache(a) + enddo + + do i = 1,10 + a(i) = i + !$acc cache(a) + enddo + +end subroutine test1 +end module test +! { dg-prune-output "Deleted" } +! { dg-prune-output "ACC cache unimplemented" } diff --git a/gcc/testsuite/gfortran.dg/goacc/loop-2.f95 b/gcc/testsuite/gfortran.dg/goacc/loop-2.f95 new file mode 100644 index 0000000..f85691e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/loop-2.f95 @@ -0,0 +1,649 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +! TODO: nested kernels are allowed in 2.0 + +program test + implicit none + integer :: i, j + + !$acc kernels + !$acc loop auto + DO i = 1,10 + ENDDO + !$acc loop gang + DO i = 1,10 + ENDDO + !$acc loop gang(5) + DO i = 1,10 + ENDDO + !$acc loop gang(num:5) + DO i = 1,10 + ENDDO + !$acc loop gang(static:5) + DO i = 1,10 + ENDDO + !$acc loop gang(static:*) + DO i = 1,10 + ENDDO + !$acc loop gang + DO i = 1,10 + !$acc loop vector + DO j = 1,10 + ENDDO + !$acc loop worker + DO j = 1,10 + ENDDO + !$acc loop gang ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + ENDDO + !$acc loop seq gang ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop worker + DO i = 1,10 + ENDDO + !$acc loop worker(5) + DO i = 1,10 + ENDDO + !$acc loop worker(num:5) + DO i = 1,10 + ENDDO + !$acc loop worker + DO i = 1,10 + !$acc loop vector + DO j = 1,10 + ENDDO + !$acc loop worker ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + !$acc loop gang ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + ENDDO + !$acc loop seq worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop gang worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop vector + DO i = 1,10 + ENDDO + !$acc loop vector(5) + DO i = 1,10 + ENDDO + !$acc loop vector(length:5) + DO i = 1,10 + ENDDO + !$acc loop vector + DO i = 1,10 + !$acc loop vector ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + !$acc loop worker ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + !$acc loop gang ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + ENDDO + !$acc loop seq vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop gang vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop worker vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop auto + DO i = 1,10 + ENDDO + !$acc loop seq auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop gang auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop worker auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop vector auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop tile ! { dg-error "Unclassifiable" } + DO i = 1,10 + ENDDO + !$acc loop tile() ! { dg-error "Syntax error" } + DO i = 1,10 + ENDDO + !$acc loop tile(1) + DO i = 1,10 + ENDDO + !$acc loop tile(2) + DO i = 1,10 + ENDDO + !$acc loop tile(6-2) + DO i = 1,10 + ENDDO + !$acc loop tile(6+2) + DO i = 1,10 + ENDDO + !$acc loop tile(*) + DO i = 1,10 + ENDDO + !$acc loop tile(*, 1) + DO i = 1,10 + DO j = 1,10 + ENDDO + ENDDO + !$acc loop tile(-1) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop tile(i) ! { dg-error "constant expression" } + do i = 1,10 + enddo + !$acc loop tile(2, 2, 1) ! { dg-error "not enough DO loops for tiled" } + do i = 1, 3 + do j = 4, 6 + end do + end do + !$acc loop tile(2, 2) + do i = 1, 5, 2 + do j = i + 1, 7, i ! { dg-error "tiled loops don.t form rectangular iteration space" } + end do + end do + !$acc loop vector tile(*) + DO i = 1,10 + ENDDO + !$acc loop worker tile(*) + DO i = 1,10 + ENDDO + !$acc loop gang tile(*) + DO i = 1,10 + ENDDO + !$acc loop vector gang tile(*) + DO i = 1,10 + ENDDO + !$acc loop vector worker tile(*) + DO i = 1,10 + ENDDO + !$acc loop gang worker tile(*) + DO i = 1,10 + ENDDO + !$acc end kernels + + + !$acc parallel + !$acc loop auto + DO i = 1,10 + ENDDO + !$acc loop gang + DO i = 1,10 + ENDDO + !$acc loop gang(5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc loop gang(num:5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc loop gang(static:5) + DO i = 1,10 + ENDDO + !$acc loop gang(static:*) + DO i = 1,10 + ENDDO + !$acc loop gang + DO i = 1,10 + !$acc loop vector + DO j = 1,10 + ENDDO + !$acc loop worker + DO j = 1,10 + ENDDO + !$acc loop gang ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + ENDDO + !$acc loop seq gang ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop worker + DO i = 1,10 + ENDDO + !$acc loop worker(5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc loop worker(num:5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc loop worker + DO i = 1,10 + !$acc loop vector + DO j = 1,10 + ENDDO + !$acc loop worker ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + !$acc loop gang ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + ENDDO + !$acc loop seq worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop gang worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop vector + DO i = 1,10 + ENDDO + !$acc loop vector(5) + DO i = 1,10 + ENDDO + !$acc loop vector(length:5) + DO i = 1,10 + ENDDO + !$acc loop vector + DO i = 1,10 + !$acc loop vector ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + !$acc loop worker ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + !$acc loop gang ! { dg-error "not allowed" } + DO j = 1,10 + ENDDO + ENDDO + !$acc loop seq vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop gang vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop worker vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop auto + DO i = 1,10 + ENDDO + !$acc loop seq auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop gang auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop worker auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc loop vector auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc loop tile ! { dg-error "Unclassifiable" } + DO i = 1,10 + ENDDO + !$acc loop tile() ! { dg-error "Syntax error" } + DO i = 1,10 + ENDDO + !$acc loop tile(1) + DO i = 1,10 + ENDDO + !$acc loop tile(*) + DO i = 1,10 + ENDDO + !$acc loop tile(2) + DO i = 1,10 + DO j = 1,10 + ENDDO + ENDDO + !$acc loop tile(-1) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop tile(i) ! { dg-error "constant expression" } + do i = 1,10 + enddo + !$acc loop tile(2, 2, 1) ! { dg-error "not enough DO loops for tiled" } + do i = 1, 3 + do j = 4, 6 + end do + end do + !$acc loop tile(2, 2) + do i = 1, 5, 2 + do j = i + 1, 7, i ! { dg-error "tiled loops don.t form rectangular iteration space" } + end do + end do + !$acc loop vector tile(*) + DO i = 1,10 + ENDDO + !$acc loop worker tile(*) + DO i = 1,10 + ENDDO + !$acc loop gang tile(*) + DO i = 1,10 + ENDDO + !$acc loop vector gang tile(*) + DO i = 1,10 + ENDDO + !$acc loop vector worker tile(*) + DO i = 1,10 + ENDDO + !$acc loop gang worker tile(*) + DO i = 1,10 + ENDDO + !$acc end parallel + + !$acc kernels loop auto + DO i = 1,10 + ENDDO + !$acc kernels loop gang + DO i = 1,10 + ENDDO + !$acc kernels loop gang(5) + DO i = 1,10 + ENDDO + !$acc kernels loop gang(num:5) + DO i = 1,10 + ENDDO + !$acc kernels loop gang(static:5) + DO i = 1,10 + ENDDO + !$acc kernels loop gang(static:*) + DO i = 1,10 + ENDDO + !$acc kernels loop gang + DO i = 1,10 + !$acc kernels loop gang + DO j = 1,10 + ENDDO + ENDDO + !$acc kernels loop seq gang ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc kernels loop worker + DO i = 1,10 + ENDDO + !$acc kernels loop worker(5) + DO i = 1,10 + ENDDO + !$acc kernels loop worker(num:5) + DO i = 1,10 + ENDDO + !$acc kernels loop worker + DO i = 1,10 + !$acc kernels loop worker + DO j = 1,10 + ENDDO + !$acc kernels loop gang + DO j = 1,10 + ENDDO + ENDDO + !$acc kernels loop seq worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc kernels loop gang worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc kernels loop vector + DO i = 1,10 + ENDDO + !$acc kernels loop vector(5) + DO i = 1,10 + ENDDO + !$acc kernels loop vector(length:5) + DO i = 1,10 + ENDDO + !$acc kernels loop vector + DO i = 1,10 + !$acc kernels loop vector + DO j = 1,10 + ENDDO + !$acc kernels loop worker + DO j = 1,10 + ENDDO + !$acc kernels loop gang + DO j = 1,10 + ENDDO + ENDDO + !$acc kernels loop seq vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc kernels loop gang vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc kernels loop worker vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc kernels loop auto + DO i = 1,10 + ENDDO + !$acc kernels loop seq auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc kernels loop gang auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc kernels loop worker auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc kernels loop vector auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc kernels loop tile ! { dg-error "Unclassifiable" } + DO i = 1,10 + ENDDO + !$acc kernels loop tile() ! { dg-error "Syntax error" } + DO i = 1,10 + ENDDO + !$acc kernels loop tile(1) + DO i = 1,10 + ENDDO + !$acc kernels loop tile(*) + DO i = 1,10 + ENDDO + !$acc kernels loop tile(*, 1) + DO i = 1,10 + DO j = 1,10 + ENDDO + ENDDO + !$acc kernels loop tile(-1) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc kernels loop tile(i) ! { dg-error "constant expression" } + do i = 1,10 + enddo + !$acc kernels loop tile(2, 2, 1) ! { dg-error "not enough DO loops for tiled" } + do i = 1, 3 + do j = 4, 6 + end do + end do + !$acc kernels loop tile(2, 2) + do i = 1, 5, 2 + do j = i + 1, 7, i ! { dg-error "tiled loops don.t form rectangular iteration space" } + end do + end do + !$acc kernels loop vector tile(*) + DO i = 1,10 + ENDDO + !$acc kernels loop worker tile(*) + DO i = 1,10 + ENDDO + !$acc kernels loop gang tile(*) + DO i = 1,10 + ENDDO + !$acc kernels loop vector gang tile(*) + DO i = 1,10 + ENDDO + !$acc kernels loop vector worker tile(*) + DO i = 1,10 + ENDDO + !$acc kernels loop gang worker tile(*) + DO i = 1,10 + ENDDO + + !$acc parallel loop auto + DO i = 1,10 + ENDDO + !$acc parallel loop gang + DO i = 1,10 + ENDDO + !$acc parallel loop gang(5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc parallel loop gang(num:5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc parallel loop gang(static:5) + DO i = 1,10 + ENDDO + !$acc parallel loop gang(static:*) + DO i = 1,10 + ENDDO + !$acc parallel loop gang + DO i = 1,10 + !$acc parallel loop gang + DO j = 1,10 + ENDDO + ENDDO + !$acc parallel loop seq gang ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc parallel loop worker + DO i = 1,10 + ENDDO + !$acc parallel loop worker(5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc parallel loop worker(num:5) ! { dg-error "non-static" } + DO i = 1,10 + ENDDO + !$acc parallel loop worker + DO i = 1,10 + !$acc parallel loop worker + DO j = 1,10 + ENDDO + !$acc parallel loop gang + DO j = 1,10 + ENDDO + ENDDO + !$acc parallel loop seq worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc parallel loop gang worker ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc parallel loop vector + DO i = 1,10 + ENDDO + !$acc parallel loop vector(5) + DO i = 1,10 + ENDDO + !$acc parallel loop vector(length:5) + DO i = 1,10 + ENDDO + !$acc parallel loop vector + DO i = 1,10 + !$acc parallel loop vector + DO j = 1,10 + ENDDO + !$acc parallel loop worker + DO j = 1,10 + ENDDO + !$acc parallel loop gang + DO j = 1,10 + ENDDO + ENDDO + !$acc parallel loop seq vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc parallel loop gang vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc parallel loop worker vector ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc parallel loop auto + DO i = 1,10 + ENDDO + !$acc parallel loop seq auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc parallel loop gang auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc parallel loop worker auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + !$acc parallel loop vector auto ! { dg-error "conflicts with" } + DO i = 1,10 + ENDDO + + !$acc parallel loop tile ! { dg-error "Unclassifiable" } + DO i = 1,10 + ENDDO + !$acc parallel loop tile() ! { dg-error "Syntax error" } + DO i = 1,10 + ENDDO + !$acc parallel loop tile(1) + DO i = 1,10 + ENDDO + !$acc parallel loop tile(*) + DO i = 1,10 + ENDDO + !$acc parallel loop tile(*, 1) + DO i = 1,10 + DO j = 1,10 + ENDDO + ENDDO + !$acc parallel loop tile(-1) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc parallel loop tile(i) ! { dg-error "constant expression" } + do i = 1,10 + enddo + !$acc parallel loop tile(2, 2, 1) ! { dg-error "not enough DO loops for tiled" } + do i = 1, 3 + do j = 4, 6 + end do + end do + !$acc parallel loop tile(2, 2) + do i = 1, 5, 2 + do j = i + 1, 7, i ! { dg-error "tiled loops don.t form rectangular iteration space" } + end do + end do + !$acc parallel loop vector tile(*) + DO i = 1,10 + ENDDO + !$acc parallel loop worker tile(*) + DO i = 1,10 + ENDDO + !$acc parallel loop gang tile(*) + DO i = 1,10 + ENDDO + !$acc parallel loop vector gang tile(*) + DO i = 1,10 + ENDDO + !$acc parallel loop vector worker tile(*) + DO i = 1,10 + ENDDO + !$acc parallel loop gang worker tile(*) + DO i = 1,10 + ENDDO +end
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/loop-3.f95 b/gcc/testsuite/gfortran.dg/goacc/loop-3.f95 new file mode 100644 index 0000000..2a866c7 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/loop-3.f95 @@ -0,0 +1,55 @@ +! { dg-do compile } +! { dg-additional-options "-std=f2008" } + +subroutine test1 + implicit none + integer :: i, j + + ! !$acc end loop not required by spec + !$acc loop + do i = 1,5 + enddo + !$acc end loop ! { dg-warning "Redundant" } + + !$acc loop + do i = 1,5 + enddo + j = 1 + !$acc end loop ! { dg-error "Unexpected" } + + !$acc parallel + !$acc loop + do i = 1,5 + enddo + !$acc end parallel + !$acc end loop ! { dg-error "Unexpected" } + + ! OpenACC supports Fortran 2008 do concurrent statement + !$acc loop + do concurrent (i = 1:5) + end do + + !$acc loop + outer_loop: do i = 1, 5 + inner_loop: do j = 1,5 + if (i .eq. j) cycle outer_loop + if (i .ne. j) exit outer_loop ! { dg-error "EXIT statement" } + end do inner_loop + end do outer_loop + + outer_loop1: do i = 1, 5 + !$acc loop + inner_loop1: do j = 1,5 + if (i .eq. j) cycle outer_loop1 ! { dg-error "CYCLE statement" } + end do inner_loop1 + end do outer_loop1 + + !$acc loop collapse(2) + outer_loop2: do i = 1, 5 + inner_loop2: do j = 1,5 + if (i .eq. j) cycle outer_loop2 ! { dg-error "CYCLE statement" } + if (i .ne. j) exit outer_loop2 ! { dg-error "EXIT statement" } + end do inner_loop2 + end do outer_loop2 +end subroutine test1 + diff --git a/gcc/testsuite/gfortran.dg/goacc/loop-tree-1.f90 b/gcc/testsuite/gfortran.dg/goacc/loop-tree-1.f90 new file mode 100644 index 0000000..966e75b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/loop-tree-1.f90 @@ -0,0 +1,48 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original -std=f2008" } + +! test for tree-dump-original and spaces-commas + +program test + implicit none + integer :: i, j, k, m, sum + REAL :: a(64), b(64), c(64) + + !$acc kernels + !$acc loop collapse(2) + DO i = 1,10 + DO j = 1,10 + ENDDO + ENDDO + + !$acc loop independent gang (3) + DO i = 1,10 + !$acc loop worker(3) ! { dg-error "work-sharing region may not be closely nested inside of work-sharing, critical, ordered, master or explicit task region" } + DO j = 1,10 + !$acc loop vector(5) + DO k = 1,10 + ENDDO + ENDDO + ENDDO + !$acc end kernels + + sum = 0 + !$acc parallel + !$acc loop private(m) reduction(+:sum) + DO i = 1,10 + sum = sum + 1 + ENDDO + !$acc end parallel + +end program test +! { dg-final { scan-tree-dump-times "pragma acc loop" 5 "original" } } + +! { dg-final { scan-tree-dump-times "collapse\\(2\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "independent" 1 "original" } } +! { dg-final { scan-tree-dump-times "gang\\(num: 3\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "worker\\(3\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "vector\\(5\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "private\\(m\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "reduction\\(\\+:sum\\)" 1 "original" } } +! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/omp.f95 b/gcc/testsuite/gfortran.dg/goacc/omp.f95 new file mode 100644 index 0000000..24f639f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/omp.f95 @@ -0,0 +1,66 @@ +! { dg-do compile } +! { dg-additional-options "-fopenmp" } + +module test +contains + subroutine ichi + implicit none + integer :: i + !$acc parallel + !$omp do ! { dg-error "cannot be specified" } + do i = 1,5 + enddo + !$acc end parallel + end subroutine ichi + + subroutine ni + implicit none + integer :: i + !$omp parallel + !$acc loop ! { dg-error "cannot be specified" } + do i = 1,5 + enddo + !$omp end parallel + end subroutine ni + + subroutine san + implicit none + integer :: i + !$omp do + !$acc loop ! { dg-error "Unexpected" } + do i = 1,5 + enddo + end subroutine san + + subroutine yon + implicit none + integer :: i + !$acc loop + !$omp do ! { dg-error "Expected DO loop" } + do i = 1,5 + enddo + end subroutine yon + + subroutine go + implicit none + integer :: i, j + + !$omp parallel + do i = 1,5 + !$acc kernels ! { dg-error "cannot be specified" } + do j = 1,5 + enddo + !$acc end kernels + enddo + !$omp end parallel + end subroutine go + + subroutine roku + implicit none + + !$acc data + !$omp parallel ! { dg-error "cannot be specified" } + !$omp end parallel + !$acc end data + end subroutine roku +end module test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-clauses.f95 b/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-clauses.f95 new file mode 100644 index 0000000..c37208c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-clauses.f95 @@ -0,0 +1,96 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +! test clauses added in OpenACC ver 2.0 + +program test + implicit none + integer :: i, a(10), b(5:7) + integer, parameter :: acc_async_noval = -1 + integer, parameter :: acc_async_sync = -2 + logical :: l + + ! async + !$acc kernels async(i) + !$acc end kernels + !$acc parallel async(i) + !$acc end parallel + + !$acc kernels async(0, 1) { dg-error "Unclassifiable" } + !$acc parallel async(0, 1) { dg-error "Unclassifiable" } + + !$acc kernels async + !$acc end kernels + !$acc parallel async + !$acc end parallel + + !$acc kernels async(acc_async_noval) + !$acc end kernels + !$acc parallel async(acc_async_noval) + !$acc end parallel + + !$acc kernels async(acc_async_sync) + !$acc end kernels + !$acc parallel async(acc_async_sync) + !$acc end parallel + + !$acc kernels async() { dg-error "Invalid character" } + !$acc parallel async() { dg-error "Invalid character" } + + !$acc kernels async("a") { dg-error "Unclassifiable" } + !$acc parallel async("a") { dg-error "Unclassifiable" } + + !$acc kernels async(.true.) { dg-error "Unclassifiable" } + !$acc parallel async(.true.) { dg-error "Unclassifiable" } + + ! default(none) + !$acc kernels default(none) + !$acc end kernels + !$acc parallel default(none) + !$acc end parallel + + !$acc kernels default (none) + !$acc end kernels + !$acc parallel default (none) + !$acc end parallel + + !$acc kernels default ( none ) + !$acc end kernels + !$acc parallel default ( none ) + !$acc end parallel + + !$acc kernels default { dg-error "Unclassifiable" } + !$acc parallel default { dg-error "Unclassifiable" } + + !$acc kernels default() { dg-error "Unclassifiable" } + !$acc parallel default() { dg-error "Unclassifiable" } + + !$acc kernels default(i) { dg-error "Unclassifiable" } + !$acc parallel default(i) { dg-error "Unclassifiable" } + + !$acc kernels default(1) { dg-error "Unclassifiable" } + !$acc parallel default(1) { dg-error "Unclassifiable" } + + ! Wait + !$acc kernels wait (l) ! { dg-error "INTEGER" } + !$acc end kernels + !$acc kernels wait (.true.) ! { dg-error "INTEGER" } + !$acc end kernels + !$acc kernels wait (i, 1) + !$acc end kernels + !$acc kernels wait (a) ! { dg-error "INTEGER" } + !$acc end kernels + !$acc kernels wait (b(5:6)) ! { dg-error "INTEGER" } + !$acc end kernels + + !$acc parallel wait (l) ! { dg-error "INTEGER" } + !$acc end parallel + !$acc parallel wait (.true.) ! { dg-error "INTEGER" } + !$acc end parallel + !$acc parallel wait (i, 1) + !$acc end parallel + !$acc parallel wait (a) ! { dg-error "INTEGER" } + !$acc end parallel + !$acc parallel wait (b(5:6)) ! { dg-error "INTEGER" } + !$acc end parallel +end diff --git a/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-regions.f95 b/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-regions.f95 new file mode 100644 index 0000000..8b8e989 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/parallel-kernels-regions.f95 @@ -0,0 +1,55 @@ +! { dg-do compile } + +! OpenACC 2.0 allows nested parallel/kernels regions, but this is not yet +! supported. + +program test + implicit none + + integer :: i + + !$acc parallel + !$acc kernels ! { dg-bogus "kernels construct inside of parallel region" "not implemented" { xfail *-*-* } } + !$acc end kernels + !$acc end parallel + + !$acc parallel + !$acc parallel ! { dg-bogus "parallel construct inside of parallel region" "not implemented" { xfail *-*-* } } + !$acc end parallel + !$acc end parallel + + !$acc parallel + !$acc parallel ! { dg-bogus "parallel construct inside of parallel region" "not implemented" { xfail *-*-* } } + !$acc end parallel + !$acc kernels ! { dg-bogus "kernels construct inside of parallel region" "not implemented" { xfail *-*-* } } + !$acc end kernels + !$acc end parallel + + !$acc kernels + !$acc kernels ! { dg-bogus "kernels construct inside of kernels region" "not implemented" { xfail *-*-* } } + !$acc end kernels + !$acc end kernels + + !$acc kernels + !$acc parallel ! { dg-bogus "parallel construct inside of kernels region" "not implemented" { xfail *-*-* } } + !$acc end parallel + !$acc end kernels + + !$acc kernels + !$acc parallel ! { dg-bogus "parallel construct inside of kernels region" "not implemented" { xfail *-*-* } } + !$acc end parallel + !$acc kernels ! { dg-bogus "kernels construct inside of kernels region" "not implemented" { xfail *-*-* } } + !$acc end kernels + !$acc end kernels + + !$acc parallel + !$acc data ! { dg-error "data construct inside of parallel region" } + !$acc end data + !$acc end parallel + + !$acc kernels + !$acc data ! { dg-error "data construct inside of kernels region" } + !$acc end data + !$acc end kernels + +end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/parallel-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/parallel-tree.f95 new file mode 100644 index 0000000..48061b1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/parallel-tree.f95 @@ -0,0 +1,41 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-original" } + +! test for tree-dump-original and spaces-commas + +program test + implicit none + integer :: q, i, j, k, m, n, o, p, r, s, t, u, v, w + logical :: l + + !$acc parallel if(l) async num_gangs(i) num_workers(i) vector_length(i) & + !$acc reduction(max:q), copy(i), copyin(j), copyout(k), create(m) & + !$acc present(o), pcopy(p), pcopyin(r), pcopyout(s), pcreate(t) & + !$acc deviceptr(u), private(v), firstprivate(w) + !$acc end parallel + +end program test +! { dg-final { scan-tree-dump-times "pragma acc parallel" 1 "original" } } + +! { dg-final { scan-tree-dump-times "if" 1 "original" } } +! { dg-final { scan-tree-dump-times "async" 1 "original" } } +! { dg-final { scan-tree-dump-times "num_gangs" 1 "original" } } +! { dg-final { scan-tree-dump-times "num_workers" 1 "original" } } +! { dg-final { scan-tree-dump-times "vector_length" 1 "original" } } + +! { dg-final { scan-tree-dump-times "reduction\\(max:q\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_tofrom:i\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_to:j\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_from:k\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(force_alloc:m\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "map\\(force_present:o\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(tofrom:p\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(to:r\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(from:s\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "map\\(alloc:t\\)" 1 "original" } } + +! { dg-final { scan-tree-dump-times "map\\(force_deviceptr:u\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "private\\(v\\)" 1 "original" } } +! { dg-final { scan-tree-dump-times "firstprivate\\(w\\)" 1 "original" } } +! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/parameter.f95 b/gcc/testsuite/gfortran.dg/goacc/parameter.f95 new file mode 100644 index 0000000..1364181 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/parameter.f95 @@ -0,0 +1,32 @@ +! { dg-do compile } + +module test +contains + subroutine oacc1 + implicit none + integer :: i + integer, parameter :: a = 1 + !$acc declare device_resident (a) ! { dg-error "PARAMETER" } + !$acc data copy (a) ! { dg-error "not a variable" } + !$acc end data + !$acc data deviceptr (a) ! { dg-error "not a variable" } + !$acc end data + !$acc parallel private (a) ! { dg-error "not a variable" } + !$acc end parallel + !$acc host_data use_device (a) ! { dg-error "not a variable" } + !$acc end host_data + !$acc parallel loop reduction(+:a) ! { dg-error "not a variable" } + do i = 1,5 + enddo + !$acc end parallel loop + !$acc parallel loop + do i = 1,5 + !$acc cache (a) ! TODO: This must fail, as in openacc-1_0-branch + enddo + !$acc end parallel loop + !$acc update device (a) ! { dg-error "not a variable" } + !$acc update host (a) ! { dg-error "not a variable" } + !$acc update self (a) ! { dg-error "not a variable" } + end subroutine oacc1 +end module test +! { dg-prune-output "unimplemented" } diff --git a/gcc/testsuite/gfortran.dg/goacc/private-1.f95 b/gcc/testsuite/gfortran.dg/goacc/private-1.f95 new file mode 100644 index 0000000..23ce95a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/private-1.f95 @@ -0,0 +1,37 @@ +! { dg-do compile } +! { dg-additional-options "-fdump-tree-omplower" } + +! test for implicit private clauses in do loops + +program test + implicit none + integer :: i, j, k + + !$acc parallel + !$acc loop + do i = 1, 100 + end do + !$acc end parallel + + !$acc parallel + !$acc loop + do i = 1, 100 + do j = 1, 100 + end do + end do + !$acc end parallel + + !$acc parallel + !$acc loop + do i = 1, 100 + do j = 1, 100 + do k = 1, 100 + end do + end do + end do + !$acc end parallel +end program test +! { dg-final { scan-tree-dump-times "pragma omp target oacc_parallel" 3 "omplower" } } +! { dg-final { scan-tree-dump-times "private\\(i\\)" 3 "omplower" } } +! { dg-final { scan-tree-dump-times "private\\(j\\)" 2 "omplower" } } +! { dg-final { scan-tree-dump-times "private\\(k\\)" 1 "omplower" } } diff --git a/gcc/testsuite/gfortran.dg/goacc/private-2.f95 b/gcc/testsuite/gfortran.dg/goacc/private-2.f95 new file mode 100644 index 0000000..4b038f2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/private-2.f95 @@ -0,0 +1,39 @@ +! { dg-do compile } + +! test for implicit private clauses in do loops + +program test + implicit none + integer :: i, j, k, a(10) + + !$acc parallel + !$acc loop + do i = 1, 100 + end do + !$acc end parallel + + !$acc parallel + !$acc loop + do i = 1, 100 + do j = 1, 100 + end do + end do + !$acc end parallel + + !$acc data copy(a) + + if(mod(1,10) .eq. 0) write(*,'(i5)') i + + do i = 1, 100 + !$acc parallel + !$acc loop + do j = 1, 100 + do k = 1, 100 + end do + end do + !$acc end parallel + end do + + !$acc end data + +end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/private-3.f95 b/gcc/testsuite/gfortran.dg/goacc/private-3.f95 new file mode 100644 index 0000000..aa12a56 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/private-3.f95 @@ -0,0 +1,23 @@ +! { dg-do compile } + +! test for private variables in a reduction clause + +program test + implicit none + integer, parameter :: n = 100 + integer :: i, k + +! FIXME: This causes an ICE in the gimplifier. +! !$acc parallel private (k) reduction (+:k) +! do i = 1, n +! k = k + 1 +! end do +! !$acc end parallel + + !$acc parallel private (k) + !$acc loop reduction (+:k) + do i = 1, n + k = k + 1 + end do + !$acc end parallel +end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/pure-elemental-procedures.f95 b/gcc/testsuite/gfortran.dg/goacc/pure-elemental-procedures.f95 new file mode 100644 index 0000000..726e8e9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/pure-elemental-procedures.f95 @@ -0,0 +1,78 @@ +! { dg-do compile } +! { dg-additional-options "-std=f2008 -fcoarray=single" } + +module test + implicit none +contains + elemental subroutine test1 + !$acc parallel ! { dg-error "may not appear in PURE procedures" } + end subroutine test1 + + pure subroutine test2 + !$acc parallel ! { dg-error "may not appear in PURE procedures" } + end subroutine test2 + + ! Implicit pure + elemental real function test3(x) + real, intent(in) :: x + !$acc parallel ! { dg-error "may not appear in PURE procedures" } + test3 = x*x + end function test3 + + pure real function test4(x) + real, intent(in) :: x + !$acc parallel ! { dg-error "may not appear in PURE procedures" } + test4 = x + end function test4 + + subroutine test5 + real :: x = 0.0 + integer :: i + !$acc parallel loop collapse(1) reduction(+:x) + do i = 1,10 + x = x + 0.3 + enddo + print *, x + end subroutine test5 + + real function test6(x) + real :: x + integer :: i + !$acc parallel loop collapse(1) reduction(+:x) + do i = 1,10 + x = x + 0.3 + enddo + test6 = x + end function test6 + + impure elemental real function test7(x) + real, intent(in) :: x + !$acc parallel + test7 = x + !$acc end parallel + end function test7 + + subroutine test8 + real :: x = 0.0 + integer :: i + !$acc parallel loop collapse(1) reduction(+:x) + do i = 1,10 + critical ! { dg-error "CRITICAL block inside of" } + x = x + 0.3 + end critical + enddo + print *, x + end subroutine test8 + + real function test9(n) + integer, value :: n + BLOCK + integer i + real sum + !$acc loop reduction(+:sum) + do i=1, n + sum = sum + sin(real(i)) + end do + END BLOCK + end function test9 +end module test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/reduction-2.f95 b/gcc/testsuite/gfortran.dg/goacc/reduction-2.f95 new file mode 100644 index 0000000..ffcec70 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/reduction-2.f95 @@ -0,0 +1,21 @@ +! { dg-do compile } + +program reduction + integer, parameter :: n = 40, c = 10 + integer :: i, sum + + call redsub (sum, n, c) +end program reduction + +subroutine redsub(sum, n, c) + integer :: sum, n, c + + sum = 0 + + !$acc parallel vector_length(n) copyin (n, c) + !$acc loop reduction(+:sum) + do i = 1, n + sum = sum + c + end do + !$acc end parallel +end subroutine redsub diff --git a/gcc/testsuite/gfortran.dg/goacc/reduction.f95 b/gcc/testsuite/gfortran.dg/goacc/reduction.f95 new file mode 100644 index 0000000..833230a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/reduction.f95 @@ -0,0 +1,138 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +subroutine foo (ia1) +integer :: i1, i2, i3 +integer, dimension (*) :: ia1 +integer, dimension (10) :: ia2 +real :: r1 +real, dimension (5) :: ra1 +double precision :: d1 +double precision, dimension (4) :: da1 +complex :: c1 +complex, dimension (7) :: ca1 +logical :: l1 +logical, dimension (3) :: la1 +character (5) :: a1 +type t + integer :: i +end type +type(t) :: t1 +type(t), dimension (2) :: ta1 +real, pointer :: p1 => NULL() +integer, allocatable :: aa1 (:,:) +save i2 +common /blk/ i1 + +!$acc parallel reduction (+:ia2) +!$acc end parallel +!$acc parallel reduction (+:ra1) +!$acc end parallel +!$acc parallel reduction (+:ca1) +!$acc end parallel +!$acc parallel reduction (+:da1) +!$acc end parallel +!$acc parallel reduction (.and.:la1) +!$acc end parallel +!$acc parallel reduction (+:i3, r1, d1, c1) +!$acc end parallel +!$acc parallel reduction (*:i3, r1, d1, c1) +!$acc end parallel +!$acc parallel reduction (-:i3, r1, d1, c1) +!$acc end parallel +!$acc parallel reduction (.and.:l1) +!$acc end parallel +!$acc parallel reduction (.or.:l1) +!$acc end parallel +!$acc parallel reduction (.eqv.:l1) +!$acc end parallel +!$acc parallel reduction (.neqv.:l1) +!$acc end parallel +!$acc parallel reduction (min:i3, r1, d1) +!$acc end parallel +!$acc parallel reduction (max:i3, r1, d1) +!$acc end parallel +!$acc parallel reduction (iand:i3) +!$acc end parallel +!$acc parallel reduction (ior:i3) +!$acc end parallel +!$acc parallel reduction (ieor:i3) +!$acc end parallel +!$acc parallel reduction (+:/blk/) ! { dg-error "Syntax error" } +!$acc end parallel ! { dg-error "Unexpected" } +!$acc parallel reduction (*:p1) ! { dg-error "POINTER object" } +!$acc end parallel +!$acc parallel reduction (-:aa1) +!$acc end parallel +!$acc parallel reduction (*:ia1) ! { dg-error "Assumed size" } +!$acc end parallel +!$acc parallel reduction (+:l1) ! { dg-error "OMP DECLARE REDUCTION \\+ not found for type LOGICAL" } +!$acc end parallel +!$acc parallel reduction (*:la1) ! { dg-error "OMP DECLARE REDUCTION \\* not found for type LOGICAL" } +!$acc end parallel +!$acc parallel reduction (-:a1) ! { dg-error "OMP DECLARE REDUCTION - not found for type CHARACTER" } +!$acc end parallel +!$acc parallel reduction (+:t1) ! { dg-error "OMP DECLARE REDUCTION \\+ not found for type TYPE" } +!$acc end parallel +!$acc parallel reduction (*:ta1) ! { dg-error "OMP DECLARE REDUCTION \\* not found for type TYPE" } +!$acc end parallel +!$acc parallel reduction (.and.:i3) ! { dg-error "OMP DECLARE REDUCTION \\.and\\. not found for type INTEGER" } +!$acc end parallel +!$acc parallel reduction (.or.:ia2) ! { dg-error "OMP DECLARE REDUCTION \\.or\\. not found for type INTEGER" } +!$acc end parallel +!$acc parallel reduction (.eqv.:r1) ! { dg-error "OMP DECLARE REDUCTION \\.eqv\\. not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (.neqv.:ra1) ! { dg-error "OMP DECLARE REDUCTION \\.neqv\\. not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (.and.:d1) ! { dg-error "OMP DECLARE REDUCTION \\.and\\. not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (.or.:da1) ! { dg-error "OMP DECLARE REDUCTION \\.or\\. not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (.eqv.:c1) ! { dg-error "OMP DECLARE REDUCTION \\.eqv\\. not found for type COMPLEX" } +!$acc end parallel +!$acc parallel reduction (.neqv.:ca1) ! { dg-error "OMP DECLARE REDUCTION \\.neqv\\. not found for type COMPLEX" } +!$acc end parallel +!$acc parallel reduction (.and.:a1) ! { dg-error "OMP DECLARE REDUCTION \\.and\\. not found for type CHARACTER" } +!$acc end parallel +!$acc parallel reduction (.or.:t1) ! { dg-error "OMP DECLARE REDUCTION \\.or\\. not found for type TYPE" } +!$acc end parallel +!$acc parallel reduction (.eqv.:ta1) ! { dg-error "OMP DECLARE REDUCTION \\.eqv\\. not found for type TYPE" } +!$acc end parallel +!$acc parallel reduction (min:c1) ! { dg-error "OMP DECLARE REDUCTION min not found for type COMPLEX" } +!$acc end parallel +!$acc parallel reduction (max:ca1) ! { dg-error "OMP DECLARE REDUCTION max not found for type COMPLEX" } +!$acc end parallel +!$acc parallel reduction (max:l1) ! { dg-error "OMP DECLARE REDUCTION max not found for type LOGICAL" } +!$acc end parallel +!$acc parallel reduction (min:la1) ! { dg-error "OMP DECLARE REDUCTION min not found for type LOGICAL" } +!$acc end parallel +!$acc parallel reduction (max:a1) ! { dg-error "OMP DECLARE REDUCTION max not found for type CHARACTER" } +!$acc end parallel +!$acc parallel reduction (min:t1) ! { dg-error "OMP DECLARE REDUCTION min not found for type TYPE" } +!$acc end parallel +!$acc parallel reduction (max:ta1) ! { dg-error "OMP DECLARE REDUCTION max not found for type TYPE" } +!$acc end parallel +!$acc parallel reduction (iand:r1) ! { dg-error "OMP DECLARE REDUCTION iand not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (ior:ra1) ! { dg-error "OMP DECLARE REDUCTION ior not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (ieor:d1) ! { dg-error "OMP DECLARE REDUCTION ieor not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (ior:da1) ! { dg-error "OMP DECLARE REDUCTION ior not found for type REAL" } +!$acc end parallel +!$acc parallel reduction (iand:c1) ! { dg-error "OMP DECLARE REDUCTION iand not found for type COMPLEX" } +!$acc end parallel +!$acc parallel reduction (ior:ca1) ! { dg-error "OMP DECLARE REDUCTION ior not found for type COMPLEX" } +!$acc end parallel +!$acc parallel reduction (ieor:l1) ! { dg-error "OMP DECLARE REDUCTION ieor not found for type LOGICAL" } +!$acc end parallel +!$acc parallel reduction (iand:la1) ! { dg-error "OMP DECLARE REDUCTION iand not found for type LOGICAL" } +!$acc end parallel +!$acc parallel reduction (ior:a1) ! { dg-error "OMP DECLARE REDUCTION ior not found for type CHARACTER" } +!$acc end parallel +!$acc parallel reduction (ieor:t1) ! { dg-error "OMP DECLARE REDUCTION ieor not found for type TYPE" } +!$acc end parallel +!$acc parallel reduction (iand:ta1) ! { dg-error "OMP DECLARE REDUCTION iand not found for type TYPE" } +!$acc end parallel + +end subroutine diff --git a/gcc/testsuite/gfortran.dg/goacc/routine-1.f90 b/gcc/testsuite/gfortran.dg/goacc/routine-1.f90 new file mode 100644 index 0000000..67c5f11 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/routine-1.f90 @@ -0,0 +1,37 @@ +! { dg-do compile } + + integer, parameter :: n = 10 + integer :: a(n), i + integer, external :: fact + i = 1 + !$acc routine (fact) ! { dg-error "Unexpected \\\!\\\$ACC ROUTINE" } + !$acc routine () ! { dg-error "Syntax error in \\\!\\\$ACC ROUTINE \\\( NAME \\\)" } + !$acc parallel + !$acc loop + do i = 1, n + a(i) = fact (i) + call incr (a(i)) + end do + !$acc end parallel + do i = 1, n + write (*, "(I10)") a(i) + end do +end +recursive function fact (x) result (res) + integer, intent(in) :: x + integer :: res + res = 1 + !$acc routine ! { dg-error "Unexpected \\\!\\\$ACC ROUTINE" } + if (x < 1) then + res = 1 + else + res = x * fact (x - 1) + end if +end function fact +subroutine incr (x) + integer, intent(inout) :: x + integer i + i = 0 + !$acc routine ! { dg-error "Unexpected \\\!\\\$ACC ROUTINE" } + x = x + 1 +end subroutine incr diff --git a/gcc/testsuite/gfortran.dg/goacc/routine-2.f90 b/gcc/testsuite/gfortran.dg/goacc/routine-2.f90 new file mode 100644 index 0000000..3be3351 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/routine-2.f90 @@ -0,0 +1,17 @@ +! { dg-do compile } + + module m1 + contains + recursive function mfact (x) result (res) + integer, intent(in) :: x + integer :: res + integer i + i = 0 + !$acc routine ! { dg-error "Unexpected \\\!\\\$ACC ROUTINE" } + if (x < 1) then + res = 1 + else + res = x * mfact (x - 1) + end if + end function mfact + end module m1 diff --git a/gcc/testsuite/gfortran.dg/goacc/sentinel-free-form.f95 b/gcc/testsuite/gfortran.dg/goacc/sentinel-free-form.f95 new file mode 100644 index 0000000..1a3189c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/sentinel-free-form.f95 @@ -0,0 +1,21 @@ +! { dg-do compile } + +program test + implicit none + + integer :: i + real :: x + + ! sentinel may only be preceeded by white space + x = 0.0 !$acc parallel ! comment + ! sentinel must appear as a single word + ! $acc parallel ! comment + !$ acc parallel ! { dg-error "Unclassifiable statement" } + ! directive lines must have space after sentinel + !$accparallel ! { dg-warning "followed by a space" } + do i = 1,10 + x = x + 0.3 + enddo + !$acc end parallel ! { dg-error "Unexpected" } + print *, x +end
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/several-directives.f95 b/gcc/testsuite/gfortran.dg/goacc/several-directives.f95 new file mode 100644 index 0000000..8fb97b5 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/several-directives.f95 @@ -0,0 +1,6 @@ +! { dg-do compile } + +program test + ! only one directive-name may appear in directive + !$acc parallel kernels ! { dg-error "Unclassifiable OpenACC directive" } +end
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/sie.f95 b/gcc/testsuite/gfortran.dg/goacc/sie.f95 new file mode 100644 index 0000000..2d66026 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/sie.f95 @@ -0,0 +1,252 @@ +! { dg-do compile } +! { dg-additional-options "-fmax-errors=100" } + +! tests async, num_gangs, num_workers, vector_length, gang, worker, vector clauses + +program test + implicit none + + integer :: i + + !$acc parallel async + !$acc end parallel + + !$acc parallel async(3) + !$acc end parallel + + !$acc parallel async(i) + !$acc end parallel + + !$acc parallel async(i+1) + !$acc end parallel + + !$acc parallel async(-1) + !$acc end parallel + + !$acc parallel async(0) + !$acc end parallel + + !$acc parallel async() ! { dg-error "Invalid character in name" } + + !$acc parallel async(1.5) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel async(.true.) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel async("1") ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc kernels async + !$acc end kernels + + !$acc kernels async(3) + !$acc end kernels + + !$acc kernels async(i) + !$acc end kernels + + !$acc kernels async(i+1) + !$acc end kernels + + !$acc kernels async(-1) + !$acc end kernels + + !$acc kernels async(0) + !$acc end kernels + + !$acc kernels async() ! { dg-error "Invalid character in name" } + + !$acc kernels async(1.5) ! { dg-error "scalar INTEGER expression" } + !$acc end kernels + + !$acc kernels async(.true.) ! { dg-error "scalar INTEGER expression" } + !$acc end kernels + + !$acc kernels async("1") ! { dg-error "scalar INTEGER expression" } + !$acc end kernels + + + !$acc parallel num_gangs ! { dg-error "Unclassifiable OpenACC directive" } + + !$acc parallel num_gangs(3) + !$acc end parallel + + !$acc parallel num_gangs(i) + !$acc end parallel + + !$acc parallel num_gangs(i+1) + !$acc end parallel + + !$acc parallel num_gangs(-1) ! { dg-warning "must be positive" } + !$acc end parallel + + !$acc parallel num_gangs(0) ! { dg-warning "must be positive" } + !$acc end parallel + + !$acc parallel num_gangs() ! { dg-error "Invalid character in name" } + + !$acc parallel num_gangs(1.5) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel num_gangs(.true.) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel num_gangs("1") ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + + !$acc parallel num_workers ! { dg-error "Unclassifiable OpenACC directive" } + + !$acc parallel num_workers(3) + !$acc end parallel + + !$acc parallel num_workers(i) + !$acc end parallel + + !$acc parallel num_workers(i+1) + !$acc end parallel + + !$acc parallel num_workers(-1) ! { dg-warning "must be positive" } + !$acc end parallel + + !$acc parallel num_workers(0) ! { dg-warning "must be positive" } + !$acc end parallel + + !$acc parallel num_workers() ! { dg-error "Invalid character in name" } + + !$acc parallel num_workers(1.5) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel num_workers(.true.) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel num_workers("1") ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + + !$acc parallel vector_length ! { dg-error "Unclassifiable OpenACC directive" } + + !$acc parallel vector_length(3) + !$acc end parallel + + !$acc parallel vector_length(i) + !$acc end parallel + + !$acc parallel vector_length(i+1) + !$acc end parallel + + !$acc parallel vector_length(-1) ! { dg-warning "must be positive" } + !$acc end parallel + + !$acc parallel vector_length(0) ! { dg-warning "must be positive" } + !$acc end parallel + + !$acc parallel vector_length() ! { dg-error "Invalid character in name" } + + !$acc parallel vector_length(1.5) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel vector_length(.true.) ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + !$acc parallel vector_length("1") ! { dg-error "scalar INTEGER expression" } + !$acc end parallel + + + !$acc loop gang + do i = 1,10 + enddo + !$acc loop gang(3) + do i = 1,10 + enddo + !$acc loop gang(i) + do i = 1,10 + enddo + !$acc loop gang(i+1) + do i = 1,10 + enddo + !$acc loop gang(-1) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop gang(0) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop gang() ! { dg-error "Invalid character in name" } + do i = 1,10 + enddo + !$acc loop gang(1.5) ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + !$acc loop gang(.true.) ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + !$acc loop gang("1") ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + + + !$acc loop worker + do i = 1,10 + enddo + !$acc loop worker(3) + do i = 1,10 + enddo + !$acc loop worker(i) + do i = 1,10 + enddo + !$acc loop worker(i+1) + do i = 1,10 + enddo + !$acc loop worker(-1) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop worker(0) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop worker() ! { dg-error "Invalid character in name" } + do i = 1,10 + enddo + !$acc loop worker(1.5) ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + !$acc loop worker(.true.) ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + !$acc loop worker("1") ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + + + !$acc loop vector + do i = 1,10 + enddo + !$acc loop vector(3) + do i = 1,10 + enddo + !$acc loop vector(i) + do i = 1,10 + enddo + !$acc loop vector(i+1) + do i = 1,10 + enddo + !$acc loop vector(-1) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop vector(0) ! { dg-warning "must be positive" } + do i = 1,10 + enddo + !$acc loop vector() ! { dg-error "Invalid character in name" } + do i = 1,10 + enddo + !$acc loop vector(1.5) ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + !$acc loop vector(.true.) ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + !$acc loop vector("1") ! { dg-error "scalar INTEGER expression" } + do i = 1,10 + enddo + +end program test
\ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/goacc/subarrays.f95 b/gcc/testsuite/gfortran.dg/goacc/subarrays.f95 new file mode 100644 index 0000000..4b3ef42 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/subarrays.f95 @@ -0,0 +1,41 @@ +! { dg-do compile } +program test + implicit none + integer :: a(10), b(10, 10), c(3:7), i + + !$acc parallel copy(a(1:5)) + !$acc end parallel + !$acc parallel copy(a(1 + 0 : 5 + 2)) + !$acc end parallel + !$acc parallel copy(a(:3)) + !$acc end parallel + !$acc parallel copy(a(3:)) + !$acc end parallel + !$acc parallel copy(a(:)) + !$acc end parallel + !$acc parallel copy(a(2:3,2:3)) + ! { dg-error "Rank mismatch" "" { target *-*-* } 16 } + ! { dg-error "'a' in MAP clause" "" { target *-*-* } 16 } + !$acc end parallel + !$acc parallel copy (a(:11)) ! { dg-warning "Upper array reference" } + !$acc end parallel + !$acc parallel copy (a(i:)) + !$acc end parallel + + !$acc parallel copy (a(:b)) + ! { dg-error "Array index" "" { target *-*-* } 25 } + ! { dg-error "'a' in MAP clause" "" { target *-*-* } 25 } + !$acc end parallel + + !$acc parallel copy (b(1:3,2:4)) + !$acc end parallel + !$acc parallel copy (b(2:3)) + ! { dg-error "Rank mismatch" "" { target *-*-* } 32 } + ! { dg-error "'b' in MAP clause" "" { target *-*-* } 32 } + !$acc end parallel + !$acc parallel copy (b(1:, 4:6)) + !$acc end parallel + + !$acc parallel copy (c(2:)) ! { dg-warning "Lower array reference" } + !$acc end parallel +end program test diff --git a/gcc/testsuite/gfortran.dg/gomp/map-1.f90 b/gcc/testsuite/gfortran.dg/gomp/map-1.f90 new file mode 100644 index 0000000..e4b8b86 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/map-1.f90 @@ -0,0 +1,110 @@ +subroutine test(aas) + implicit none + + integer :: i, j(10), k(10, 10), aas(*) + integer, save :: tp + !$omp threadprivate(tp) + integer, parameter :: p = 1 + + type t + integer :: i, j(10) + end type t + + type(t) :: tt + + !$omp target map(i) + !$omp end target + + !$omp target map(j) + !$omp end target + + !$omp target map(p) ! { dg-error "Object 'p' is not a variable" } + !$omp end target + + !$omp target map(j(1)) + !$omp end target + + !$omp target map(j(i)) + !$omp end target + + !$omp target map(j(i:)) + !$omp end target + + !$omp target map(j(:i)) + !$omp end target + + !$omp target map(j(i:i+1)) + !$omp end target + + !$omp target map(j(11)) ! { dg-warning "out of bounds" } + !$omp end target + + !$omp target map(j(:11)) ! { dg-warning "out of bounds" } + !$omp end target + + !$omp target map(j(0:)) ! { dg-warning "out of bounds" } + !$omp end target + + !$omp target map(j(5:4)) + !$omp end target + + !$omp target map(j(5:)) + !$omp end target + + !$omp target map(j(:5)) + !$omp end target + + !$omp target map(j(:)) + !$omp end target + + !$omp target map(j(1:9:2)) ! { dg-error "Stride should not be specified for array section in MAP clause" } + !$omp end target + + !$omp target map(aas(5:)) + !$omp end target + ! { dg-error "Rightmost upper bound of assumed size array section not specified" "" { target *-*-* } 63 } + ! { dg-error "'aas' in MAP clause at \\\(1\\\) is not a proper array section" "" { target *-*-* } 63 } + + !$omp target map(aas(:)) + !$omp end target + ! { dg-error "Rightmost upper bound of assumed size array section not specified" "" { target *-*-* } 68 } + ! { dg-error "'aas' in MAP clause at \\\(1\\\) is not a proper array section" "" { target *-*-* } 68 } + + !$omp target map(aas) ! { dg-error "The upper bound in the last dimension must appear" "" { xfail *-*-* } } + !$omp end target + + !$omp target map(aas(5:7)) + !$omp end target + + !$omp target map(aas(:7)) + !$omp end target + + !$omp target map(k(5:)) + !$omp end target + ! { dg-error "Rank mismatch in array reference" "" { target *-*-* } 82 } + ! { dg-error "'k' in MAP clause at \\\(1\\\) is not a proper array section" "" { target *-*-* } 82 } + + !$omp target map(k(5:,:,3)) + !$omp end target + ! { dg-error "Rank mismatch in array reference" "" { target *-*-* } 87 } + ! { dg-error "'k' in MAP clause at \\\(1\\\) is not a proper array section" "" { target *-*-* } 87 } + + !$omp target map(tt) + !$omp end target + + !$omp target map(tt%i) ! { dg-error "Syntax error in OpenMP variable list" } + !$omp end target ! { dg-error "Unexpected !\\\$OMP END TARGET statement" } + + !$omp target map(tt%j) ! { dg-error "Syntax error in OpenMP variable list" } + !$omp end target ! { dg-error "Unexpected !\\\$OMP END TARGET statement" } + + ! broken test + !$omp target map(tt%j(1)) ! { dg-error "Syntax error in OpenMP variable list" } + !$omp end target ! { dg-error "Unexpected !\\\$OMP END TARGET statement" } + + !$omp target map(tt%j(1:)) ! { dg-error "Syntax error in OpenMP variable list" } + !$omp end target ! { dg-error "Unexpected !\\\$OMP END TARGET statement" } + + !$omp target map(tp) ! { dg-error "THREADPRIVATE object 'tp' in MAP clause" } + !$omp end target +end subroutine test diff --git a/gcc/testsuite/gfortran.dg/openacc-define-1.f90 b/gcc/testsuite/gfortran.dg/openacc-define-1.f90 new file mode 100644 index 0000000..42f4073 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/openacc-define-1.f90 @@ -0,0 +1,7 @@ +! { dg-options "-cpp" } +! { dg-do preprocess } +! { dg-require-effective-target fopenacc } + +#ifdef _OPENACC +# error _OPENACC defined +#endif diff --git a/gcc/testsuite/gfortran.dg/openacc-define-2.f90 b/gcc/testsuite/gfortran.dg/openacc-define-2.f90 new file mode 100644 index 0000000..8ad1bd5 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/openacc-define-2.f90 @@ -0,0 +1,7 @@ +! { dg-options "-cpp -fno-openacc" } +! { dg-do preprocess } +! { dg-require-effective-target fopenacc } + +#ifdef _OPENACC +# error _OPENACC defined +#endif diff --git a/gcc/testsuite/gfortran.dg/openacc-define-3.f90 b/gcc/testsuite/gfortran.dg/openacc-define-3.f90 new file mode 100644 index 0000000..b6c296e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/openacc-define-3.f90 @@ -0,0 +1,11 @@ +! { dg-options "-cpp -fopenacc" } +! { dg-do preprocess } +! { dg-require-effective-target fopenacc } + +#ifndef _OPENACC +# error _OPENACC not defined +#endif + +#if _OPENACC != 201306 +# error _OPENACC defined to wrong value +#endif diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 00872ab..e51d07d 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -788,6 +788,15 @@ proc check_effective_target_fgraphite {} { } "-O1 -fgraphite"] } +# Return 1 if compilation with -fopenacc is error-free for trivial +# code, 0 otherwise. + +proc check_effective_target_fopenacc {} { + return [check_no_compiler_messages fopenacc object { + void foo (void) { } + } "-fopenacc"] +} + # Return 1 if compilation with -fopenmp is error-free for trivial # code, 0 otherwise. diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 41f99d1..735ce5c 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -208,19 +208,19 @@ enum omp_clause_code { (c_parser_omp_variable_list). */ OMP_CLAUSE_ERROR = 0, - /* OpenMP clause: private (variable_list). */ + /* OpenACC/OpenMP clause: private (variable_list). */ OMP_CLAUSE_PRIVATE, /* OpenMP clause: shared (variable_list). */ OMP_CLAUSE_SHARED, - /* OpenMP clause: firstprivate (variable_list). */ + /* OpenACC/OpenMP clause: firstprivate (variable_list). */ OMP_CLAUSE_FIRSTPRIVATE, /* OpenMP clause: lastprivate (variable_list). */ OMP_CLAUSE_LASTPRIVATE, - /* OpenMP clause: reduction (operator:variable_list). + /* OpenACC/OpenMP clause: reduction (operator:variable_list). OMP_CLAUSE_REDUCTION_CODE: The tree_code of the operator. Operand 1: OMP_CLAUSE_REDUCTION_INIT: Stmt-list to initialize the var. Operand 2: OMP_CLAUSE_REDUCTION_MERGE: Stmt-list to merge private var @@ -253,13 +253,48 @@ enum omp_clause_code { /* OpenMP clause: to (variable-list). */ OMP_CLAUSE_TO, - /* OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list). */ + /* OpenACC clauses: {copy, copyin, copyout, create, delete, deviceptr, + device, host (self), present, present_or_copy (pcopy), present_or_copyin + (pcopyin), present_or_copyout (pcopyout), present_or_create (pcreate)} + (variable-list). + + OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list). */ OMP_CLAUSE_MAP, + /* Internal structure to hold OpenACC cache directive's variable-list. + #pragma acc cache (variable-list). */ + OMP_CLAUSE__CACHE_, + + /* OpenACC clause: device_resident (variable_list). */ + OMP_CLAUSE_DEVICE_RESIDENT, + + /* OpenACC clause: use_device (variable_list). */ + OMP_CLAUSE_USE_DEVICE, + + /* OpenACC clause: gang [(gang-argument-list)]. + Where + gang-argument-list: [gang-argument-list, ] gang-argument + gang-argument: [num:] integer-expression + | static: size-expression + size-expression: * | integer-expression. */ + OMP_CLAUSE_GANG, + + /* OpenACC clause: async [(integer-expression)]. */ + OMP_CLAUSE_ASYNC, + + /* OpenACC clause: wait [(integer-expression-list)]. */ + OMP_CLAUSE_WAIT, + + /* OpenACC clause: auto. */ + OMP_CLAUSE_AUTO, + + /* OpenACC clause: seq. */ + OMP_CLAUSE_SEQ, + /* Internal clause: temporary for combined loops expansion. */ OMP_CLAUSE__LOOPTEMP_, - /* OpenMP clause: if (scalar-expression). */ + /* OpenACC/OpenMP clause: if (scalar-expression). */ OMP_CLAUSE_IF, /* OpenMP clause: num_threads (integer-expression). */ @@ -277,7 +312,7 @@ enum omp_clause_code { /* OpenMP clause: default. */ OMP_CLAUSE_DEFAULT, - /* OpenMP clause: collapse (constant-integer-expression). */ + /* OpenACC/OpenMP clause: collapse (constant-integer-expression). */ OMP_CLAUSE_COLLAPSE, /* OpenMP clause: untied. */ @@ -333,7 +368,25 @@ enum omp_clause_code { /* Internally used only clause, holding _Cilk_for # of iterations on OMP_PARALLEL. */ - OMP_CLAUSE__CILK_FOR_COUNT_ + OMP_CLAUSE__CILK_FOR_COUNT_, + + /* OpenACC clause: independent. */ + OMP_CLAUSE_INDEPENDENT, + + /* OpenACC clause: worker [( [num:] integer-expression)]. */ + OMP_CLAUSE_WORKER, + + /* OpenACC clause: vector [( [length:] integer-expression)]. */ + OMP_CLAUSE_VECTOR, + + /* OpenACC clause: num_gangs (integer-expression). */ + OMP_CLAUSE_NUM_GANGS, + + /* OpenACC clause: num_workers (integer-expression). */ + OMP_CLAUSE_NUM_WORKERS, + + /* OpenACC clause: vector_length (integer-expression). */ + OMP_CLAUSE_VECTOR_LENGTH }; #undef DEFTREESTRUCT @@ -1172,24 +1225,6 @@ enum omp_clause_depend_kind OMP_CLAUSE_DEPEND_LAST }; -enum omp_clause_map_kind -{ - OMP_CLAUSE_MAP_ALLOC, - OMP_CLAUSE_MAP_TO, - OMP_CLAUSE_MAP_FROM, - OMP_CLAUSE_MAP_TOFROM, - /* The following kind is an internal only map kind, used for pointer based - array sections. OMP_CLAUSE_SIZE for these is not the pointer size, - which is implicitly POINTER_SIZE_UNITS, but the bias. */ - OMP_CLAUSE_MAP_POINTER, - /* Also internal, behaves like OMP_CLAUS_MAP_TO, but additionally any - OMP_CLAUSE_MAP_POINTER records consecutive after it which have addresses - falling into that range will not be ignored if OMP_CLAUSE_MAP_TO_PSET - wasn't mapped already. */ - OMP_CLAUSE_MAP_TO_PSET, - OMP_CLAUSE_MAP_LAST -}; - enum omp_clause_proc_bind_kind { /* Numbers should match omp_proc_bind_t enum in omp.h. */ @@ -1261,7 +1296,8 @@ struct GTY(()) tree_omp_clause { enum omp_clause_default_kind default_kind; enum omp_clause_schedule_kind schedule_kind; enum omp_clause_depend_kind depend_kind; - enum omp_clause_map_kind map_kind; + /* See include/gomp-constants.h for enum gomp_map_kind's values. */ + unsigned char map_kind; enum omp_clause_proc_bind_kind proc_bind_kind; enum tree_code reduction_code; } GTY ((skip)) subcode; diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index ac16e24..5443ab5 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -4194,7 +4194,7 @@ estimate_num_insns (gimple stmt, eni_weights *weights) return (estimate_num_insns_seq (gimple_try_eval (stmt), weights) + estimate_num_insns_seq (gimple_try_cleanup (stmt), weights)); - /* OpenMP directives are generally very expensive. */ + /* OMP directives are generally very expensive. */ case GIMPLE_OMP_RETURN: case GIMPLE_OMP_SECTIONS_SWITCH: diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 526e617..f2e6d3a 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -73,6 +73,7 @@ #include "expr.h" /* FIXME: For STACK_SAVEAREA_MODE and SAVE_NONLOCAL. */ #include "langhooks.h" #include "gimple-low.h" +#include "gomp-constants.h" /* The object of this pass is to lower the representation of a set of nested @@ -850,7 +851,7 @@ static void note_nonlocal_vla_type (struct nesting_info *info, tree type); /* A subroutine of convert_nonlocal_reference_op. Create a local variable in the nested function with DECL_VALUE_EXPR set to reference the true variable in the parent function. This is used both for debug info - and in OpenMP lowering. */ + and in OMP lowering. */ static tree get_nonlocal_debug_decl (struct nesting_info *info, tree decl) @@ -1399,7 +1400,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, break; case GIMPLE_OMP_TARGET: - if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION) + if (!is_gimple_omp_offloaded (stmt)) { save_suppress = info->suppress_expansion; convert_nonlocal_omp_clauses (gimple_omp_target_clauses_ptr (stmt), @@ -1418,7 +1419,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, decl = get_chain_decl (info); c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP); OMP_CLAUSE_DECL (c) = decl; - OMP_CLAUSE_MAP_KIND (c) = OMP_CLAUSE_MAP_TO; + OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TO); OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl); OMP_CLAUSE_CHAIN (c) = gimple_omp_target_clauses (stmt); gimple_omp_target_set_clauses (as_a <gomp_target *> (stmt), c); @@ -1503,7 +1504,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, /* A subroutine of convert_local_reference. Create a local variable in the parent function with DECL_VALUE_EXPR set to reference the - field in FRAME. This is used both for debug info and in OpenMP + field in FRAME. This is used both for debug info and in OMP lowering. */ static tree @@ -1968,7 +1969,7 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, break; case GIMPLE_OMP_TARGET: - if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION) + if (!is_gimple_omp_offloaded (stmt)) { save_suppress = info->suppress_expansion; convert_local_omp_clauses (gimple_omp_target_clauses_ptr (stmt), wi); @@ -1984,7 +1985,7 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, (void) get_frame_type (info); c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP); OMP_CLAUSE_DECL (c) = info->frame_decl; - OMP_CLAUSE_MAP_KIND (c) = OMP_CLAUSE_MAP_TOFROM; + OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_TOFROM); OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (info->frame_decl); OMP_CLAUSE_CHAIN (c) = gimple_omp_target_clauses (stmt); gimple_omp_target_set_clauses (as_a <gomp_target *> (stmt), c); @@ -2301,7 +2302,7 @@ convert_tramp_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, } case GIMPLE_OMP_TARGET: - if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION) + if (!is_gimple_omp_offloaded (stmt)) { *handled_ops_p = false; return NULL_TREE; @@ -2400,7 +2401,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, break; case GIMPLE_OMP_TARGET: - if (gimple_omp_target_kind (stmt) != GF_OMP_TARGET_KIND_REGION) + if (!is_gimple_omp_offloaded (stmt)) { walk_body (convert_gimple_call, NULL, info, gimple_omp_body_ptr (stmt)); break; @@ -2425,8 +2426,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, { c = build_omp_clause (gimple_location (stmt), OMP_CLAUSE_MAP); OMP_CLAUSE_DECL (c) = decl; - OMP_CLAUSE_MAP_KIND (c) - = i ? OMP_CLAUSE_MAP_TO : OMP_CLAUSE_MAP_TOFROM; + OMP_CLAUSE_SET_MAP_KIND (c, i ? GOMP_MAP_TO : GOMP_MAP_TOFROM); OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl); OMP_CLAUSE_CHAIN (c) = gimple_omp_target_clauses (stmt); gimple_omp_target_set_clauses (as_a <gomp_target *> (stmt), diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 5773eba..d7c049f 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see #include "value-prof.h" #include "wide-int-print.h" #include "internal-fn.h" +#include "gomp-constants.h" /* Local functions, macros and variables. */ static const char *op_symbol (const_tree); @@ -350,6 +351,12 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE__LOOPTEMP_: name = "_looptemp_"; goto print_remap; + case OMP_CLAUSE_DEVICE_RESIDENT: + name = "device_resident"; + goto print_remap; + case OMP_CLAUSE_USE_DEVICE: + name = "use_device"; + goto print_remap; print_remap: pp_string (pp, name); pp_left_paren (pp); @@ -528,20 +535,41 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) pp_string (pp, "map("); switch (OMP_CLAUSE_MAP_KIND (clause)) { - case OMP_CLAUSE_MAP_ALLOC: - case OMP_CLAUSE_MAP_POINTER: + case GOMP_MAP_ALLOC: + case GOMP_MAP_POINTER: pp_string (pp, "alloc"); break; - case OMP_CLAUSE_MAP_TO: - case OMP_CLAUSE_MAP_TO_PSET: + case GOMP_MAP_TO: + case GOMP_MAP_TO_PSET: pp_string (pp, "to"); break; - case OMP_CLAUSE_MAP_FROM: + case GOMP_MAP_FROM: pp_string (pp, "from"); break; - case OMP_CLAUSE_MAP_TOFROM: + case GOMP_MAP_TOFROM: pp_string (pp, "tofrom"); break; + case GOMP_MAP_FORCE_ALLOC: + pp_string (pp, "force_alloc"); + break; + case GOMP_MAP_FORCE_TO: + pp_string (pp, "force_to"); + break; + case GOMP_MAP_FORCE_FROM: + pp_string (pp, "force_from"); + break; + case GOMP_MAP_FORCE_TOFROM: + pp_string (pp, "force_tofrom"); + break; + case GOMP_MAP_FORCE_PRESENT: + pp_string (pp, "force_present"); + break; + case GOMP_MAP_FORCE_DEALLOC: + pp_string (pp, "force_dealloc"); + break; + case GOMP_MAP_FORCE_DEVICEPTR: + pp_string (pp, "force_deviceptr"); + break; default: gcc_unreachable (); } @@ -552,10 +580,10 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) if (OMP_CLAUSE_SIZE (clause)) { if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (clause) == OMP_CLAUSE_MAP_POINTER) + && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER) pp_string (pp, " [pointer assign, bias: "); else if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (clause) == OMP_CLAUSE_MAP_TO_PSET) + && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_TO_PSET) pp_string (pp, " [pointer set, len: "); else pp_string (pp, " [len: "); @@ -578,6 +606,12 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) spc, flags, false); goto print_clause_size; + case OMP_CLAUSE__CACHE_: + pp_string (pp, "("); + dump_generic_node (pp, OMP_CLAUSE_DECL (clause), + spc, flags, false); + goto print_clause_size; + case OMP_CLAUSE_NUM_TEAMS: pp_string (pp, "num_teams("); dump_generic_node (pp, OMP_CLAUSE_NUM_TEAMS_EXPR (clause), @@ -651,6 +685,99 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) pp_right_paren (pp); break; + case OMP_CLAUSE_GANG: + pp_string (pp, "gang"); + if (OMP_CLAUSE_GANG_EXPR (clause) != NULL_TREE) + { + pp_string (pp, "(num: "); + dump_generic_node (pp, OMP_CLAUSE_GANG_EXPR (clause), + spc, flags, false); + } + if (OMP_CLAUSE_GANG_STATIC_EXPR (clause) != NULL_TREE) + { + if (OMP_CLAUSE_GANG_EXPR (clause) == NULL_TREE) + pp_left_paren (pp); + else + pp_space (pp); + pp_string (pp, "static:"); + if (OMP_CLAUSE_GANG_STATIC_EXPR (clause) + == integer_minus_one_node) + pp_character (pp, '*'); + else + dump_generic_node (pp, OMP_CLAUSE_GANG_STATIC_EXPR (clause), + spc, flags, false); + } + if (OMP_CLAUSE_GANG_EXPR (clause) != NULL_TREE + || OMP_CLAUSE_GANG_STATIC_EXPR (clause) != NULL_TREE) + pp_right_paren (pp); + break; + + case OMP_CLAUSE_ASYNC: + pp_string (pp, "async"); + if (OMP_CLAUSE_ASYNC_EXPR (clause)) + { + pp_character(pp, '('); + dump_generic_node (pp, OMP_CLAUSE_ASYNC_EXPR (clause), + spc, flags, false); + pp_character(pp, ')'); + } + break; + + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_SEQ: + pp_string (pp, omp_clause_code_name[OMP_CLAUSE_CODE (clause)]); + break; + + case OMP_CLAUSE_WAIT: + pp_string (pp, "wait("); + dump_generic_node (pp, OMP_CLAUSE_WAIT_EXPR (clause), + spc, flags, false); + pp_character(pp, ')'); + break; + + case OMP_CLAUSE_WORKER: + pp_string (pp, "worker"); + if (OMP_CLAUSE_WORKER_EXPR (clause) != NULL_TREE) + { + pp_left_paren (pp); + dump_generic_node (pp, OMP_CLAUSE_WORKER_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + } + break; + + case OMP_CLAUSE_VECTOR: + pp_string (pp, "vector"); + if (OMP_CLAUSE_VECTOR_EXPR (clause) != NULL_TREE) + { + pp_left_paren (pp); + dump_generic_node (pp, OMP_CLAUSE_VECTOR_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + } + break; + + case OMP_CLAUSE_NUM_GANGS: + pp_string (pp, "num_gangs("); + dump_generic_node (pp, OMP_CLAUSE_NUM_GANGS_EXPR (clause), + spc, flags, false); + pp_character (pp, ')'); + break; + + case OMP_CLAUSE_NUM_WORKERS: + pp_string (pp, "num_workers("); + dump_generic_node (pp, OMP_CLAUSE_NUM_WORKERS_EXPR (clause), + spc, flags, false); + pp_character (pp, ')'); + break; + + case OMP_CLAUSE_VECTOR_LENGTH: + pp_string (pp, "vector_length("); + dump_generic_node (pp, OMP_CLAUSE_VECTOR_LENGTH_EXPR (clause), + spc, flags, false); + pp_character (pp, ')'); + break; + case OMP_CLAUSE_INBRANCH: pp_string (pp, "inbranch"); break; @@ -669,6 +796,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags) case OMP_CLAUSE_TASKGROUP: pp_string (pp, "taskgroup"); break; + case OMP_CLAUSE_INDEPENDENT: + pp_string (pp, "independent"); + break; default: /* Should never happen. */ @@ -2433,6 +2563,51 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, pp_string (pp, " > "); break; + case OACC_PARALLEL: + pp_string (pp, "#pragma acc parallel"); + dump_omp_clauses (pp, OACC_PARALLEL_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OACC_KERNELS: + pp_string (pp, "#pragma acc kernels"); + dump_omp_clauses (pp, OACC_KERNELS_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OACC_DATA: + pp_string (pp, "#pragma acc data"); + dump_omp_clauses (pp, OACC_DATA_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OACC_HOST_DATA: + pp_string (pp, "#pragma acc host_data"); + dump_omp_clauses (pp, OACC_HOST_DATA_CLAUSES (node), spc, flags); + goto dump_omp_body; + + case OACC_DECLARE: + pp_string (pp, "#pragma acc declare"); + dump_omp_clauses (pp, OACC_DECLARE_CLAUSES (node), spc, flags); + break; + + case OACC_UPDATE: + pp_string (pp, "#pragma acc update"); + dump_omp_clauses (pp, OACC_UPDATE_CLAUSES (node), spc, flags); + break; + + case OACC_ENTER_DATA: + pp_string (pp, "#pragma acc enter data"); + dump_omp_clauses (pp, OACC_ENTER_DATA_CLAUSES (node), spc, flags); + break; + + case OACC_EXIT_DATA: + pp_string (pp, "#pragma acc exit data"); + dump_omp_clauses (pp, OACC_EXIT_DATA_CLAUSES (node), spc, flags); + break; + + case OACC_CACHE: + pp_string (pp, "#pragma acc cache"); + dump_omp_clauses (pp, OACC_CACHE_CLAUSES (node), spc, flags); + break; + case OMP_PARALLEL: pp_string (pp, "#pragma omp parallel"); dump_omp_clauses (pp, OMP_PARALLEL_CLAUSES (node), spc, flags); @@ -2477,6 +2652,10 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, int flags, pp_string (pp, "#pragma omp distribute"); goto dump_omp_loop; + case OACC_LOOP: + pp_string (pp, "#pragma acc loop"); + goto dump_omp_loop; + case OMP_TEAMS: pp_string (pp, "#pragma omp teams"); dump_omp_clauses (pp, OMP_TEAMS_CLAUSES (node), spc, flags); diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c index c436852..67d33ed 100644 --- a/gcc/tree-streamer-in.c +++ b/gcc/tree-streamer-in.c @@ -59,6 +59,8 @@ along with GCC; see the file COPYING3. If not see #include "lto-streamer.h" #include "builtins.h" #include "ipa-chkp.h" +#include "gomp-constants.h" + /* Read a STRING_CST from the string table in DATA_IN using input block IB. */ @@ -435,8 +437,8 @@ unpack_ts_omp_clause_value_fields (struct data_in *data_in, = bp_unpack_enum (bp, omp_clause_depend_kind, OMP_CLAUSE_DEPEND_LAST); break; case OMP_CLAUSE_MAP: - OMP_CLAUSE_MAP_KIND (expr) - = bp_unpack_enum (bp, omp_clause_map_kind, OMP_CLAUSE_MAP_LAST); + OMP_CLAUSE_SET_MAP_KIND (expr, bp_unpack_enum (bp, gomp_map_kind, + GOMP_MAP_LAST)); break; case OMP_CLAUSE_PROC_BIND: OMP_CLAUSE_PROC_BIND_KIND (expr) diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c index 480fb1e..3669680a 100644 --- a/gcc/tree-streamer-out.c +++ b/gcc/tree-streamer-out.c @@ -55,6 +55,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-streamer.h" #include "data-streamer.h" #include "streamer-hooks.h" +#include "gomp-constants.h" + /* Output the STRING constant to the string table in OB. Then put the index onto the INDEX_STREAM. */ @@ -395,7 +397,7 @@ pack_ts_omp_clause_value_fields (struct output_block *ob, OMP_CLAUSE_DEPEND_KIND (expr)); break; case OMP_CLAUSE_MAP: - bp_pack_enum (bp, omp_clause_map_kind, OMP_CLAUSE_MAP_LAST, + bp_pack_enum (bp, gomp_map_kind, GOMP_MAP_LAST, OMP_CLAUSE_MAP_KIND (expr)); break; case OMP_CLAUSE_PROC_BIND: @@ -329,6 +329,14 @@ unsigned const char omp_clause_num_ops[] = 2, /* OMP_CLAUSE_FROM */ 2, /* OMP_CLAUSE_TO */ 2, /* OMP_CLAUSE_MAP */ + 2, /* OMP_CLAUSE__CACHE_ */ + 1, /* OMP_CLAUSE_DEVICE_RESIDENT */ + 1, /* OMP_CLAUSE_USE_DEVICE */ + 2, /* OMP_CLAUSE_GANG */ + 1, /* OMP_CLAUSE_ASYNC */ + 1, /* OMP_CLAUSE_WAIT */ + 0, /* OMP_CLAUSE_AUTO */ + 0, /* OMP_CLAUSE_SEQ */ 1, /* OMP_CLAUSE__LOOPTEMP_ */ 1, /* OMP_CLAUSE_IF */ 1, /* OMP_CLAUSE_NUM_THREADS */ @@ -355,6 +363,12 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_TASKGROUP */ 1, /* OMP_CLAUSE__SIMDUID_ */ 1, /* OMP_CLAUSE__CILK_FOR_COUNT_ */ + 0, /* OMP_CLAUSE_INDEPENDENT */ + 1, /* OMP_CLAUSE_WORKER */ + 1, /* OMP_CLAUSE_VECTOR */ + 1, /* OMP_CLAUSE_NUM_GANGS */ + 1, /* OMP_CLAUSE_NUM_WORKERS */ + 1, /* OMP_CLAUSE_VECTOR_LENGTH */ }; const char * const omp_clause_code_name[] = @@ -374,6 +388,14 @@ const char * const omp_clause_code_name[] = "from", "to", "map", + "_cache_", + "device_resident", + "use_device", + "gang", + "async", + "wait", + "auto", + "seq", "_looptemp_", "if", "num_threads", @@ -399,7 +421,13 @@ const char * const omp_clause_code_name[] = "sections", "taskgroup", "_simduid_", - "_Cilk_for_count_" + "_Cilk_for_count_", + "independent", + "worker", + "vector", + "num_gangs", + "num_workers", + "vector_length" }; @@ -11167,6 +11195,19 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE: switch (OMP_CLAUSE_CODE (*tp)) { + case OMP_CLAUSE_GANG: + WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 1)); + /* FALLTHRU */ + + case OMP_CLAUSE_DEVICE_RESIDENT: + case OMP_CLAUSE_USE_DEVICE: + case OMP_CLAUSE_ASYNC: + case OMP_CLAUSE_WAIT: + case OMP_CLAUSE_WORKER: + case OMP_CLAUSE_VECTOR: + case OMP_CLAUSE_NUM_GANGS: + case OMP_CLAUSE_NUM_WORKERS: + case OMP_CLAUSE_VECTOR_LENGTH: case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_SHARED: case OMP_CLAUSE_FIRSTPRIVATE: @@ -11190,6 +11231,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 0)); /* FALLTHRU */ + case OMP_CLAUSE_INDEPENDENT: case OMP_CLAUSE_NOWAIT: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_DEFAULT: @@ -11202,6 +11244,8 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_PARALLEL: case OMP_CLAUSE_SECTIONS: case OMP_CLAUSE_TASKGROUP: + case OMP_CLAUSE_AUTO: + case OMP_CLAUSE_SEQ: WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); case OMP_CLAUSE_LASTPRIVATE: @@ -11227,6 +11271,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: case OMP_CLAUSE_MAP: + case OMP_CLAUSE__CACHE_: WALK_SUBTREE (OMP_CLAUSE_DECL (*tp)); WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, 1)); WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp)); diff --git a/gcc/tree.def b/gcc/tree.def index 204c182..b4b4164 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1030,8 +1030,33 @@ DEFTREECODE (TARGET_MEM_REF, "target_mem_ref", tcc_reference, 5) chain of component references offsetting p by c. */ DEFTREECODE (MEM_REF, "mem_ref", tcc_reference, 2) -/* The ordering of the codes between OMP_PARALLEL and OMP_CRITICAL is - exposed to TREE_RANGE_CHECK. */ +/* OpenACC and OpenMP. As it is exposed in TREE_RANGE_CHECK invocations, do + not change the ordering of these codes. */ + +/* OpenACC - #pragma acc parallel [clause1 ... clauseN] + Operand 0: OACC_PARALLEL_BODY: Code to be executed in parallel. + Operand 1: OACC_PARALLEL_CLAUSES: List of clauses. */ + +DEFTREECODE (OACC_PARALLEL, "oacc_parallel", tcc_statement, 2) + +/* OpenACC - #pragma acc kernels [clause1 ... clauseN] + Operand 0: OACC_KERNELS_BODY: Sequence of kernels. + Operand 1: OACC_KERNELS_CLAUSES: List of clauses. */ + +DEFTREECODE (OACC_KERNELS, "oacc_kernels", tcc_statement, 2) + +/* OpenACC - #pragma acc data [clause1 ... clauseN] + Operand 0: OACC_DATA_BODY: Data construct body. + Operand 1: OACC_DATA_CLAUSES: List of clauses. */ + +DEFTREECODE (OACC_DATA, "oacc_data", tcc_statement, 2) + +/* OpenACC - #pragma acc host_data [clause1 ... clauseN] + Operand 0: OACC_HOST_DATA_BODY: Host_data construct body. + Operand 1: OACC_HOST_DATA_CLAUSES: List of clauses. */ + +DEFTREECODE (OACC_HOST_DATA, "oacc_host_data", tcc_statement, 2) + /* OpenMP - #pragma omp parallel [clause1 ... clauseN] Operand 0: OMP_PARALLEL_BODY: Code to be executed by all threads. Operand 1: OMP_PARALLEL_CLAUSES: List of clauses. */ @@ -1062,7 +1087,7 @@ DEFTREECODE (OMP_TASK, "omp_task", tcc_statement, 2) private. N1, N2 and INCR are required to be loop invariant integer expressions that are evaluated without any synchronization. The evaluation order, frequency of evaluation and side-effects are - unspecified by the standard. */ + unspecified by the standards. */ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6) /* OpenMP - #pragma omp simd [clause1 ... clauseN] @@ -1081,6 +1106,10 @@ DEFTREECODE (CILK_FOR, "cilk_for", tcc_statement, 6) Operands like for OMP_FOR. */ DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6) +/* OpenMP - #pragma acc loop [clause1 ... clauseN] + Operands like for OMP_FOR. */ +DEFTREECODE (OACC_LOOP, "oacc_loop", tcc_statement, 6) + /* OpenMP - #pragma omp teams [clause1 ... clauseN] Operand 0: OMP_TEAMS_BODY: Teams body. Operand 1: OMP_TEAMS_CLAUSES: List of clauses. */ @@ -1127,6 +1156,27 @@ DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1) Operand 1: OMP_CRITICAL_NAME: Identifier for critical section. */ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2) +/* OpenACC - #pragma acc cache (variable1 ... variableN) + Operand 0: OACC_CACHE_CLAUSES: List of variables (transformed into + OMP_CLAUSE__CACHE_ clauses). */ +DEFTREECODE (OACC_CACHE, "oacc_cache", tcc_statement, 1) + +/* OpenACC - #pragma acc declare [clause1 ... clauseN] + Operand 0: OACC_DECLARE_CLAUSES: List of clauses. */ +DEFTREECODE (OACC_DECLARE, "oacc_declare", tcc_statement, 1) + +/* OpenACC - #pragma acc enter data [clause1 ... clauseN] + Operand 0: OACC_ENTER_DATA_CLAUSES: List of clauses. */ +DEFTREECODE (OACC_ENTER_DATA, "oacc_enter_data", tcc_statement, 1) + +/* OpenACC - #pragma acc exit data [clause1 ... clauseN] + Operand 0: OACC_EXIT_DATA_CLAUSES: List of clauses. */ +DEFTREECODE (OACC_EXIT_DATA, "oacc_exit_data", tcc_statement, 1) + +/* OpenACC - #pragma acc update [clause1 ... clauseN] + Operand 0: OACC_UPDATE_CLAUSES: List of clauses. */ +DEFTREECODE (OACC_UPDATE, "oacc_update", tcc_statement, 1) + /* OpenMP - #pragma omp target update [clause1 ... clauseN] Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses. */ DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1) @@ -1195,12 +1195,47 @@ extern void protected_set_expr_location (tree, location_t); #define TRANSACTION_EXPR_RELAXED(NODE) \ (TRANSACTION_EXPR_CHECK (NODE)->base.public_flag) -/* OpenMP directive and clause accessors. */ +/* OpenMP and OpenACC directive and clause accessors. */ #define OMP_BODY(NODE) \ - TREE_OPERAND (TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_CRITICAL), 0) + TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_CRITICAL), 0) #define OMP_CLAUSES(NODE) \ - TREE_OPERAND (TREE_RANGE_CHECK (NODE, OMP_PARALLEL, OMP_SINGLE), 1) + TREE_OPERAND (TREE_RANGE_CHECK (NODE, OACC_PARALLEL, OMP_SINGLE), 1) + +#define OACC_PARALLEL_BODY(NODE) \ + TREE_OPERAND (OACC_PARALLEL_CHECK (NODE), 0) +#define OACC_PARALLEL_CLAUSES(NODE) \ + TREE_OPERAND (OACC_PARALLEL_CHECK (NODE), 1) + +#define OACC_KERNELS_BODY(NODE) \ + TREE_OPERAND (OACC_KERNELS_CHECK(NODE), 0) +#define OACC_KERNELS_CLAUSES(NODE) \ + TREE_OPERAND (OACC_KERNELS_CHECK(NODE), 1) + +#define OACC_DATA_BODY(NODE) \ + TREE_OPERAND (OACC_DATA_CHECK (NODE), 0) +#define OACC_DATA_CLAUSES(NODE) \ + TREE_OPERAND (OACC_DATA_CHECK (NODE), 1) + +#define OACC_HOST_DATA_BODY(NODE) \ + TREE_OPERAND (OACC_HOST_DATA_CHECK (NODE), 0) +#define OACC_HOST_DATA_CLAUSES(NODE) \ + TREE_OPERAND (OACC_HOST_DATA_CHECK (NODE), 1) + +#define OACC_CACHE_CLAUSES(NODE) \ + TREE_OPERAND (OACC_CACHE_CHECK (NODE), 0) + +#define OACC_DECLARE_CLAUSES(NODE) \ + TREE_OPERAND (OACC_DECLARE_CHECK (NODE), 0) + +#define OACC_ENTER_DATA_CLAUSES(NODE) \ + TREE_OPERAND (OACC_ENTER_DATA_CHECK (NODE), 0) + +#define OACC_EXIT_DATA_CLAUSES(NODE) \ + TREE_OPERAND (OACC_EXIT_DATA_CHECK (NODE), 0) + +#define OACC_UPDATE_CLAUSES(NODE) \ + TREE_OPERAND (OACC_UPDATE_CHECK (NODE), 0) #define OMP_PARALLEL_BODY(NODE) TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 0) #define OMP_PARALLEL_CLAUSES(NODE) TREE_OPERAND (OMP_PARALLEL_CHECK (NODE), 1) @@ -1212,7 +1247,7 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_TASKREG_BODY(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 0) #define OMP_TASKREG_CLAUSES(NODE) TREE_OPERAND (OMP_TASKREG_CHECK (NODE), 1) -#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, OMP_DISTRIBUTE) +#define OMP_LOOP_CHECK(NODE) TREE_RANGE_CHECK (NODE, OMP_FOR, OACC_LOOP) #define OMP_FOR_BODY(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 0) #define OMP_FOR_CLAUSES(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 1) #define OMP_FOR_INIT(NODE) TREE_OPERAND (OMP_LOOP_CHECK (NODE), 2) @@ -1254,7 +1289,7 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_SIZE(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE), \ OMP_CLAUSE_FROM, \ - OMP_CLAUSE_MAP), 1) + OMP_CLAUSE__CACHE_), 1) #define OMP_CLAUSE_CHAIN(NODE) TREE_CHAIN (OMP_CLAUSE_CHECK (NODE)) #define OMP_CLAUSE_DECL(NODE) \ @@ -1271,6 +1306,15 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_SECTION_LAST(NODE) \ (OMP_SECTION_CHECK (NODE)->base.private_flag) +/* True on an OACC_KERNELS statement if is represents combined kernels loop + directive. */ +#define OACC_KERNELS_COMBINED(NODE) \ + (OACC_KERNELS_CHECK (NODE)->base.private_flag) + +/* Like OACC_KERNELS_COMBINED, but for parallel loop directive. */ +#define OACC_PARALLEL_COMBINED(NODE) \ + (OACC_PARALLEL_CHECK (NODE)->base.private_flag) + /* True on an OMP_PARALLEL statement if it represents an explicit combined parallel work-sharing constructs. */ #define OMP_PARALLEL_COMBINED(NODE) \ @@ -1313,15 +1357,47 @@ extern void protected_set_expr_location (tree, location_t); #define OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE), 0) +/* OpenACC clause expressions */ +#define OMP_CLAUSE_GANG_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GANG), 0) +#define OMP_CLAUSE_GANG_STATIC_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GANG), 1) +#define OMP_CLAUSE_ASYNC_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ASYNC), 0) +#define OMP_CLAUSE_WAIT_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_WAIT), 0) +#define OMP_CLAUSE_VECTOR_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_VECTOR), 0) +#define OMP_CLAUSE_WORKER_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_WORKER), 0) +#define OMP_CLAUSE_NUM_GANGS_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_GANGS), 0) +#define OMP_CLAUSE_NUM_WORKERS_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_WORKERS), 0) +#define OMP_CLAUSE_VECTOR_LENGTH_EXPR(NODE) \ + OMP_CLAUSE_OPERAND ( \ + OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_VECTOR_LENGTH), 0) + #define OMP_CLAUSE_DEPEND_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind) #define OMP_CLAUSE_MAP_KIND(NODE) \ - (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind) + ((enum gomp_map_kind) OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind) +#define OMP_CLAUSE_SET_MAP_KIND(NODE, MAP_KIND) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind \ + = (unsigned char) (MAP_KIND)) /* Nonzero if this map clause is for array (rather than pointer) based array - section with zero bias. Both the non-decl OMP_CLAUSE_MAP and - correspoidng OMP_CLAUSE_MAP_POINTER clause are marked with this flag. */ + section with zero bias. Both the non-decl OMP_CLAUSE_MAP and corresponding + OMP_CLAUSE_MAP with GOMP_MAP_POINTER are marked with this flag. */ #define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag) diff --git a/gcc/varpool.c b/gcc/varpool.c index d43c80b..9c8f1eb 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -173,7 +173,7 @@ varpool_node::get_create (tree decl) node = varpool_node::create_empty (); node->decl = decl; - if (flag_openmp + if ((flag_openacc || flag_openmp) && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))) { node->offloadable = 1; |