Hi Tobias!

On 2026-07-14T22:38:40+0200, Tobias Burnus <[email protected]> wrote:
> Follow up to the just committed support for 'device_type(nohost)'
> on 'target' - adding now 'device_type(host)' and competing this
> feature. ('any' is also supported.)
>
> Comment before I commit it?

..., or after.  My question is: how did you test this?  I'm seeing:

    @@ -7893,7 +7893,7 @@ PASS: c-c++-common/gomp/reverse-offload-1.c (test for 
excess errors)
    PASS: c-c++-common/gomp/reverse-offload-1.c scan-tree-dump-times omplower 
"__attribute__\\(\\(omp declare target\\)\\)[\n\r]*int called_in_target1" 1
    PASS: c-c++-common/gomp/reverse-offload-1.c scan-tree-dump-times omplower 
"__attribute__\\(\\(omp declare target\\)\\)[\n\r]*int called_in_target2" 1
    PASS: c-c++-common/gomp/reverse-offload-1.c scan-tree-dump-times omplower 
"__attribute__\\(\\(omp declare target\\)\\)[\n\r]*void tg_fn" 1
    [-PASS:-]{+FAIL:+} c-c++-common/gomp/reverse-offload-1.c 
scan-tree-dump-times omplower "omp declare target[^ ]" 3

Same for C++.

..., and for AMD as well as NVIDIA GPU offloading configurations:

    UNSUPPORTED: libgomp.c/../libgomp.c-c++-common/reverse-offload-1-aux.c
    [-PASS:-]{+FAIL:+} libgomp.c/../libgomp.c-c++-common/reverse-offload-1.c 
(test for excess errors)
    [-PASS:-]{+UNRESOLVED:+} 
libgomp.c/../libgomp.c-c++-common/reverse-offload-1.c [-execution 
test-]{+compilation failed to produce executable+}

    
[...]/source-gcc/libgomp/testsuite/libgomp.c/../libgomp.c-c++-common/reverse-offload-1.c:19:12:
 error: variable 'global_var' has been referenced in offloaded code but hasn't 
been marked to be included in the offloaded code
    lto1: fatal error: errors during merging of translation units
    compilation terminated.
    gcn mkoffload: fatal error: 
[...]/build-gcc/gcc/x86_64-pc-linux-gnu-accel-amdgcn-amdhsa-gcc returned 1 exit 
status

    @@ -2549,8 +2549,8 @@ PASS: libgomp.c/../libgomp.c-c++-common/target-42.c  
(test for warnings, line 10
    PASS: libgomp.c/../libgomp.c-c++-common/target-42.c  (test for warnings, 
line 12)
    PASS: libgomp.c/../libgomp.c-c++-common/target-42.c  (test for warnings, 
line 14)
    PASS: libgomp.c/../libgomp.c-c++-common/target-42.c  (test for warnings, 
line 15)
    [-PASS:-]{+FAIL:+} libgomp.c/../libgomp.c-c++-common/target-42.c (test for 
excess errors)
    [-PASS:-]{+UNRESOLVED:+} libgomp.c/../libgomp.c-c++-common/target-42.c 
[-execution test-]{+compilation failed to produce executable+}

    [...]
    
[...]/source-gcc/libgomp/testsuite/libgomp.c/../libgomp.c-c++-common/target-42.c:4:1:
 error: function 'foo' has been referenced in offloaded code but hasn't been 
marked to be included in the offloaded code
    lto1: fatal error: errors during merging of translation units
    compilation terminated.
    gcn mkoffload: fatal error: 
[...]/build-gcc/gcc/x86_64-pc-linux-gnu-accel-amdgcn-amdhsa-gcc returned 1 exit 
status

    [-PASS:-]{+FAIL:+} libgomp.fortran/reverse-offload-1.f90   -O0  (test for 
excess errors)
    [-PASS:-]{+UNRESOLVED:+} libgomp.fortran/reverse-offload-1.f90   -O0  
[-execution test-]{+compilation failed to produce executable+}
    [Etc.]

    
[...]/source-gcc/libgomp/testsuite/libgomp.fortran/reverse-offload-1.f90:53:14: 
error: variable 'prog_var' has been referenced in offloaded code but hasn't 
been marked to be included in the offloaded code
    
[...]/source-gcc/libgomp/testsuite/libgomp.fortran/reverse-offload-1.f90:22:14: 
error: variable 'global_var' has been referenced in offloaded code but hasn't 
been marked to be included in the offloaded code
    lto1: fatal error: errors during merging of translation units
    compilation terminated.
    gcn mkoffload: fatal error: 
[...]/build-gcc/gcc/x86_64-pc-linux-gnu-accel-amdgcn-amdhsa-gcc returned 1 exit 
status

    [-PASS:-]{+FAIL:+} libgomp.fortran/reverse-offload-6.f90   -O  (test for 
excess errors)
    [-PASS:-]{+UNRESOLVED:+} libgomp.fortran/reverse-offload-6.f90   -O  
[-execution test-]{+compilation failed to produce executable+}

    
[...]/source-gcc/libgomp/testsuite/libgomp.fortran/reverse-offload-6.f90:9:14: 
error: variable 'x' has been referenced in offloaded code but hasn't been 
marked to be included in the offloaded code
    
[...]/source-gcc/libgomp/testsuite/libgomp.fortran/reverse-offload-6.f90:10:14: 
error: variable 'dev_num2' has been referenced in offloaded code but hasn't 
been marked to be included in the offloaded code
    lto1: fatal error: errors during merging of translation units
    compilation terminated.
    gcn mkoffload: fatal error: 
[...]/build-gcc/gcc/x86_64-pc-linux-gnu-accel-amdgcn-amdhsa-gcc returned 1 exit 
status

Or, is something wrong on my end?


Grüße
 Thomas


> OpenMP: Handle 'device_type(host)' on 'target'
>
> When 'device_type(host)' is specified on a target region, no offload code
> is generated for the outlined region. Additionally, it is honored for
> implicit 'declare target'.
>
> The code is executed as if 'device(omp_initial_device)' were present
> (i.e. also no issus with OMP_TARGET_OFFLOAD=mandatory).
>
> gcc/ChangeLog:
>
>       * omp-expand.cc (expand_omp_target): For 'device_type(host)',
>       invoke with device(omp_initial_device)'.
>       * omp-low.cc (create_omp_child_function): Take host_only
>       argument to prevent generating offload code.
>       scan_omp_parallel, scan_omp_task, scan_omp_target, scan_omp_teams,
>       lower_omp_target): Update call.
>       * omp-offload.cc (omp_discover_declare_target_tgt_fn_r,
>       omp_discover_declare_target_fn_r): Do not add implicit 'declare
>       target' to target regions with 'device_type(host)'.
>
> libgomp/ChangeLog:
>
>       * libgomp.texi (Implementations status): Mark 'device_type'
>       clause on target as implemented.
>       * testsuite/libgomp.c/target-device-type-3.c: New test.
>
> gcc/testsuite/ChangeLog:
>
>       * c-c++-common/gomp/target-device-type-1.c: Remove dg-sorry.
>       * gfortran.dg/gomp/target-device-type-1.f90: Likewise.
>
>  gcc/omp-expand.cc                                  | 12 +++-
>  gcc/omp-low.cc                                     | 26 ++++-----
>  gcc/omp-offload.cc                                 | 10 +++-
>  .../c-c++-common/gomp/target-device-type-1.c       |  2 +-
>  .../gfortran.dg/gomp/target-device-type-1.f90      |  2 +-
>  libgomp/libgomp.texi                               |  4 +-
>  libgomp/testsuite/libgomp.c/target-device-type-3.c | 65 
> ++++++++++++++++++++++
>  7 files changed, 97 insertions(+), 24 deletions(-)
>
> diff --git a/gcc/omp-expand.cc b/gcc/omp-expand.cc
> index 388f84eddff..ca4d5d0db9e 100644
> --- a/gcc/omp-expand.cc
> +++ b/gcc/omp-expand.cc
> @@ -10014,6 +10014,7 @@ expand_omp_target (struct omp_region *region)
>    tree clauses = gimple_omp_target_clauses (entry_stmt);
>  
>    bool is_ancestor = false;
> +  bool is_host_only = false;
>    child_fn = child_fn2 = NULL_TREE;
>    child_cfun = NULL;
>    if (offloaded)
> @@ -10021,6 +10022,9 @@ expand_omp_target (struct omp_region *region)
>        c = omp_find_clause (clauses, OMP_CLAUSE_DEVICE);
>        if (ENABLE_OFFLOADING && c)
>       is_ancestor = OMP_CLAUSE_DEVICE_ANCESTOR (c);
> +      c = omp_find_clause (clauses, OMP_CLAUSE_DEVICE_TYPE);
> +      if (c && OMP_CLAUSE_DEVICE_TYPE_KIND (c) == 
> OMP_CLAUSE_DEVICE_TYPE_HOST)
> +     is_host_only = true;
>        child_fn = gimple_omp_target_child_fn (entry_stmt);
>        child_cfun = DECL_STRUCT_FUNCTION (child_fn);
>      }
> @@ -10211,7 +10215,7 @@ expand_omp_target (struct omp_region *region)
>       {
>         if (in_lto_p)
>           DECL_PRESERVE_P (child_fn) = 1;
> -       if (!is_ancestor)
> +       if (!is_ancestor && !is_host_only)
>           vec_safe_push (offload_funcs, child_fn);
>       }
>  
> @@ -10393,8 +10397,10 @@ expand_omp_target (struct omp_region *region)
>      }
>    else
>      {
> -      c = omp_find_clause (clauses, OMP_CLAUSE_DEVICE);
> -      if (c)
> +      if (is_host_only)
> +     device = build_int_cst (integer_type_node,
> +                             GOMP_DEVICE_HOST_FALLBACK - 1);
> +      else if ((c = omp_find_clause (clauses, OMP_CLAUSE_DEVICE)) != 
> NULL_TREE)
>       {
>         device = OMP_CLAUSE_DEVICE_ID (c);
>         /* Ensure 'device' is of the correct type.  */
> diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
> index 99f73e501c0..ec421657c68 100644
> --- a/gcc/omp-low.cc
> +++ b/gcc/omp-low.cc
> @@ -2131,10 +2131,10 @@ omp_maybe_offloaded_ctx (omp_context *ctx)
>  }
>  
>  /* Build a decl for the omp child function.  It'll not contain a body
> -   yet, just the bare decl.  */
> +   yet, just the bare decl. If HOST_ONLY, do not create a device version.  */
>  
>  static void
> -create_omp_child_function (omp_context *ctx, bool task_copy)
> +create_omp_child_function (omp_context *ctx, bool task_copy, bool host_only)
>  {
>    tree decl, type, name, t;
>  
> @@ -2189,7 +2189,7 @@ create_omp_child_function (omp_context *ctx, bool 
> task_copy)
>    DECL_FUNCTION_VERSIONED (decl)
>      = DECL_FUNCTION_VERSIONED (current_function_decl);
>  
> -  if (omp_maybe_offloaded_ctx (ctx))
> +  if (omp_maybe_offloaded_ctx (ctx) && !host_only)
>      {
>        cgraph_node::get_create (decl)->offloadable = 1;
>        if (ENABLE_OFFLOADING)
> @@ -2435,7 +2435,7 @@ scan_omp_parallel (gimple_stmt_iterator *gsi, 
> omp_context *outer_ctx)
>    DECL_NAMELESS (name) = 1;
>    TYPE_NAME (ctx->record_type) = name;
>    TYPE_ARTIFICIAL (ctx->record_type) = 1;
> -  create_omp_child_function (ctx, false);
> +  create_omp_child_function (ctx, false, false);
>    gimple_omp_parallel_set_child_fn (stmt, ctx->cb.dst_fn);
>  
>    scan_sharing_clauses (gimple_omp_parallel_clauses (stmt), ctx);
> @@ -2488,7 +2488,7 @@ scan_omp_task (gimple_stmt_iterator *gsi, omp_context 
> *outer_ctx)
>    DECL_NAMELESS (name) = 1;
>    TYPE_NAME (ctx->record_type) = name;
>    TYPE_ARTIFICIAL (ctx->record_type) = 1;
> -  create_omp_child_function (ctx, false);
> +  create_omp_child_function (ctx, false, false);
>    gimple_omp_task_set_child_fn (stmt, ctx->cb.dst_fn);
>  
>    scan_sharing_clauses (gimple_omp_task_clauses (stmt), ctx);
> @@ -2502,7 +2502,7 @@ scan_omp_task (gimple_stmt_iterator *gsi, omp_context 
> *outer_ctx)
>        DECL_NAMELESS (name) = 1;
>        TYPE_NAME (ctx->srecord_type) = name;
>        TYPE_ARTIFICIAL (ctx->srecord_type) = 1;
> -      create_omp_child_function (ctx, true);
> +      create_omp_child_function (ctx, true, false);
>      }
>  
>    scan_omp (gimple_omp_body_ptr (stmt), ctx);
> @@ -3209,7 +3209,10 @@ scan_omp_target (gomp_target *stmt, omp_context 
> *outer_ctx)
>  
>    if (offloaded)
>      {
> -      create_omp_child_function (ctx, false);
> +      tree c = omp_find_clause (clauses, OMP_CLAUSE_DEVICE_TYPE);
> +      bool host_only
> +     = c && OMP_CLAUSE_DEVICE_TYPE_KIND (c) == OMP_CLAUSE_DEVICE_TYPE_HOST;
> +      create_omp_child_function (ctx, false, host_only);
>        gimple_omp_target_set_child_fn (stmt, ctx->cb.dst_fn);
>      }
>  
> @@ -3268,7 +3271,7 @@ scan_omp_teams (gomp_teams *stmt, omp_context 
> *outer_ctx)
>    DECL_NAMELESS (name) = 1;
>    TYPE_NAME (ctx->record_type) = name;
>    TYPE_ARTIFICIAL (ctx->record_type) = 1;
> -  create_omp_child_function (ctx, false);
> +  create_omp_child_function (ctx, false, false);
>    gimple_omp_teams_set_child_fn (stmt, ctx->cb.dst_fn);
>  
>    scan_sharing_clauses (gimple_omp_teams_clauses (stmt), ctx);
> @@ -13284,13 +13287,6 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, 
> omp_context *ctx)
>           DECL_HAS_VALUE_EXPR_P (new_var) = 1;
>         }
>       break;
> -     case OMP_CLAUSE_DEVICE_TYPE:
> -       /* FIXME: Ensure that 'nohost' also has not implied before that
> -          'g->have_offload = true' or an implicit declare target.  */
> -       if (OMP_CLAUSE_DEVICE_TYPE_KIND (c) == OMP_CLAUSE_DEVICE_TYPE_HOST)
> -         sorry_at (OMP_CLAUSE_LOCATION (c),
> -                   "the %<device_type(host)%> is not supported");
> -       break;
>        case OMP_CLAUSE_USES_ALLOCATORS:
>       allocator = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c);
>       tree new_allocator = lookup_decl (allocator, ctx);
> diff --git a/gcc/omp-offload.cc b/gcc/omp-offload.cc
> index 7cd2a572b7c..bbe13154d8f 100644
> --- a/gcc/omp-offload.cc
> +++ b/gcc/omp-offload.cc
> @@ -272,7 +272,10 @@ omp_discover_declare_target_tgt_fn_r (tree *tp, int 
> *walk_subtrees, void *data)
>    else if (TREE_CODE (*tp) == OMP_TARGET)
>      {
>        tree c = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE);
> -      if (c && OMP_CLAUSE_DEVICE_ANCESTOR (c))
> +      tree c2 = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE_TYPE);
> +      if ((!c || !OMP_CLAUSE_DEVICE_ANCESTOR (c))
> +       && (!c2 || (OMP_CLAUSE_DEVICE_TYPE_KIND (c2)
> +                   != OMP_CLAUSE_DEVICE_TYPE_HOST)))
>       *walk_subtrees = 0;
>      }
>    return NULL_TREE;
> @@ -286,7 +289,10 @@ omp_discover_declare_target_fn_r (tree *tp, int 
> *walk_subtrees, void *data)
>    if (TREE_CODE (*tp) == OMP_TARGET)
>      {
>        tree c = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE);
> -      if (!c || !OMP_CLAUSE_DEVICE_ANCESTOR (c))
> +      tree c2 = omp_find_clause (OMP_CLAUSES (*tp), OMP_CLAUSE_DEVICE_TYPE);
> +      if ((!c || !OMP_CLAUSE_DEVICE_ANCESTOR (c))
> +       && (!c2 || (OMP_CLAUSE_DEVICE_TYPE_KIND (c2)
> +                   != OMP_CLAUSE_DEVICE_TYPE_HOST)))
>       walk_tree_without_duplicates (&OMP_TARGET_BODY (*tp),
>                                     omp_discover_declare_target_tgt_fn_r,
>                                     data);
> diff --git a/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c 
> b/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c
> index 758330436cd..15817717daa 100644
> --- a/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c
> +++ b/gcc/testsuite/c-c++-common/gomp/target-device-type-1.c
> @@ -13,7 +13,7 @@ void f ()
>  #pragma omp target device_type ( nohost )
>    ;
>  
> -#pragma omp target device_type ( host )  // { dg-message "sorry, 
> unimplemented: the 'device_type\\(host\\)' is not supported" }
> +#pragma omp target device_type ( host )
>    ;
>  
>  }
> diff --git a/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90 
> b/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90
> index 164fc4f1fd6..fa1265f5ed2 100644
> --- a/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90
> +++ b/gcc/testsuite/gfortran.dg/gomp/target-device-type-1.f90
> @@ -10,7 +10,7 @@
>  !$omp target device_type ( nohost )
>  !$omp end target
>  
> -!$omp target device_type ( host )  ! { dg-message "sorry, unimplemented: the 
> 'device_type\\(host\\)' is not supported" }
> +!$omp target device_type ( host )
>  !$omp end target
>  
>  end
> diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
> index 63c5cf475b7..4e2bdc280e9 100644
> --- a/libgomp/libgomp.texi
> +++ b/libgomp/libgomp.texi
> @@ -580,7 +580,7 @@ to address of matching mapped list item per 5.1, Sect. 
> 2.21.7.2 @tab N @tab
>        @code{target_data}, @code{target_exit_data} and @code{target_update}
>        @tab N @tab
>  @item New @code{device_type} clause to the @code{target} directive
> -      @tab P @tab @code{device_type(host)} unsupported
> +      @tab Y @tab
>  @item @code{target_data} as composite construct @tab N @tab
>  @item @code{nowait} clause with reverse-offload @code{target} directives
>        @tab N @tab
> diff --git a/libgomp/testsuite/libgomp.c/target-device-type-3.c 
> b/libgomp/testsuite/libgomp.c/target-device-type-3.c
> new file mode 100644
> index 00000000000..faedcabdf22
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.c/target-device-type-3.c
> @@ -0,0 +1,65 @@
> +/* { dg-do run } */
> +/* { dg-additional-options -fdump-tree-ompexp } */
> +/* { dg-additional-options 
> -foffload-options=-fdump-tree-optimized-raw-asmname } */
> +
> +/* This code is supposed to run on the host independent of the current
> +   default-device-var ICV - and it shall not create any device code for
> +   neither the target region nor the called functions.  */
> +
> +// NOTE: With offloading,
> +//   UNRESOLVED:
> +// is expected for the "optimized" tests as those dumps are only enabled
> +// for the no-host side.
> +
> +
> +// Due to 'device_type(nohost)', the outlined region shall not be marked
> +// as 'target entrypoint' - nor should 'ggg' become implicitly
> +// 'declare target' -- check for the absence of those __attributes__:
> +
> +/* { dg-final { scan-tree-dump-times "omp declare target" 1 "ompexp" } } */
> +/* { dg-final { scan-tree-dump-not "omp target entrypoint" "ompexp" } } */
> +
> +
> +// Expect that GOMP_target explicitly invokes the host device, i.e.
> +// -3 == (shifted) omp_initial_device (aka host fallback)
> +
> +/* { dg-final { scan-tree-dump "__builtin_GOMP_target_ext \\(-3," "ompexp" } 
> } */
> +
> +
> +// On the device side, expect only hhh:
> +
> +/* { dg-final { scan-tree-dump "hhh" "optimized" { target offload_device } } 
> } */
> +/* { dg-final { scan-tree-dump-not "ggg" "optimized" { target offload_device 
> } } } */
> +/* { dg-final { scan-tree-dump-not "_omp_fn" "optimized" { target 
> offload_device } } } */
> +
> +
> +#include <omp.h>
> +
> +// Use 'declare target' such that -fdump-tree-optimized creates a file.
> +// Otherwise, there is dump file (only a stub assembly file)
> +// That's the only purpose of this function.
> +int hhh() { return 5; }
> +#pragma omp declare target enter(hhh)
> +
> +
> +int ggg() {
> +  return 42;
> +}
> +
> +int f(int *x) {
> +  bool initial_dev = false;
> +  #pragma omp target map(tofrom: initial_dev) device_type(host) 
> +    {
> +      initial_dev = omp_is_initial_device ();
> +      (*x) = (*x) + 1 + ggg();
> +    }
> +  if (!initial_dev)
> +    __builtin_abort ();
> +  return *x;
> +}
> +
> +int main() {
> +  int i = 5;
> +  if (f(&i) != 5 + 1 + 42)
> +    __builtin_abort();
> +}

Reply via email to