mbox series

[committed,0/4] (Partial) OpenMP 5.0 support for GCC 9

Message ID 20181108171611.GK11625@tucnak
Headers show
Series (Partial) OpenMP 5.0 support for GCC 9 | expand

Message

Jakub Jelinek Nov. 8, 2018, 5:16 p.m. UTC
Hi!

The OpenMP 5.0 specification, https://www.openmp.org/specifications/ ,
has been just released a few minutes ago and to celebrate that, I've merged
gomp-5_0-branch into trunk after bootstrapping/regtesting it on x86_64-linux and
i686-linux.

Because the amount of changes in OpenMP 5.0 is much bigger than in any of the earlier
releases of the standard, unfortunately the whole spec isn't implemented at this point,
not even for C/C++.  So, let me start by listing features that are implemented.
Unless otherwise stated, the implementation is for now for C/C++ only, Fortran to follow
after C/C++ is fully done.

New OpenMP 5.0 features in this patchset:

- task reductions, including task modifier on parallel/worksharing construct reduction
- != conditions in OpenMP loops
- C++1[147] range for loops in worksharing loop, taskloop and distribute
  (and combined/composite constructs)
- allow private or lastprivate clauses for iterator variable(s) on simd construct or
  combined/composite constructs including simd
- iterators in depend clause
- support for lvalue expressions in depend clauses (note, some expressions in depend
  clauses that got allowed very recently are still unsupported)
- mutexinoutset dependence kind (right now this is implemented in the runtime library
  as less efficient inout, but can be improved later solely on in the runtime library)
- depobj construct, depobj dependence kind and omp_depend_t
- depend clause on taskwait construct
- host teams construct (the library implementation still needs work, so that it is
  actually beneficial on NUMA setups, see below)
- cancel if clause modifier
- if and nontemporal clauses on simd (both are parsed only right now, unless I figure
  out how to propagate it through IL to the vectorizer quickly, if will either force
  no simd at all, or will cause duplication of the loop; nontemporal either will
  use nontemporal stores, or for GCC 9 will do nothing)
- defaultmap clause extensions
- hint and memory order clauses on atomic (hint is parsed and ignored by the
  implementation for now, memory order fully implemented)
- memory order clauses on flush
- support for new combined #pragma omp parallel master
  and #pragma omp {,parallel }master taskloop{, simd} constructs
- affinity display support, omp_{[sg]et_affinity_format,{display,capture}_affinity},
  OMP_DISPLAY_AFFINITY and OMP_AFFINITY_FORMAT env vars (this is implemented also
  for Fortran)
- omp_pause_resource{,_all} support, omp_pause_resource_t type (for now the
  runtime library is able to free resources on the host only; this is implemented
  also for Fortran)
- worksharing loop schedules now default to nonmonotonic with the exception of
  static schedules, nonmonotonic allowed on static, runtime and auto,
  omp_sched_monotonic modifier and OMP_SCHEDULE env var parsing changes (note,
  the runtime library is told if monotonic or nonmonotonic schedule is used
  in a backwards compatible way, but the runtime library ATM doesn't take
  advantage of nonmonotonic schedules, everything is still effectively monotonic)
- allow only use_device_ptr clause(s) on target data construct
- change data sharing for readonly variables without mutable members, they are
  no longer predetermined shared (this actually changed in earlier OpenMP standard
  releases, but was considered a mistake; for 5.0 it was decided it isn't going to
  be reverted; this makes a difference mainly when using default(none))
- allow atomic constructs in simd regions (note, for now this causes the vectorizer
  to fail to vectorize such regions)
- allow comma in between (name) and hint clause on critical construct
- device routine prototype changes (void * to const void * arguments)
- omp_lock_hint* to omp_sync_hint* changes
- partial requires construct support, only atomic_default_mem_order fully implemented

Features I'll still try to implement for GCC 9:

- make sure all expressions in the OpenMP grammar within clauses are
  assignment-expression, with the exception of array section expressions
- verify taskloop construct cancellation works
- stop diagnosing threadprivate directive after first use to allow definitions of
  variables with constructors followed by threadprivate, rather than the currently
  required workaround of extern declaration of it, followed by threadprivate directive
  followed by definition

New OpenMP 5.0 features that won't be available in GCC 9, are planned for GCC 10
or later versions as time permits:

- requires directive other than atomic_default_mem_order (parsing is implemented, but
  the rest is not)
- inscan reduction clause modifier and scan directive
- lastprivate clause with conditional modifier
- OMP_TARGET_OFFLOAD env var and target-offload-var ICV
- max-active-levels-var / nested-var ICV, omp_[sg]et_nested and OMP_NESTED changes
- omp_get_supported_active_levels API addition
- array shaping support, array sections with non-unit strides in to/from/depend clauses
- metadirective support
- declare variant support
- non-rectangular loop support, support for not perfectly nested loops
- order(concurrent) clause support
- loop construct support
- affinity clause support
- detach clause support, omp_fulfill_event
- OpenMP allocator support, omp_alloc/omp_init_allocator etc., allocate directive and clause
- use_device_addr clause support
- ancestor modifier on device clause, reverse offloading
- implicit declare target support
- lvalue expressions in map/to/from clauses
- nested declare target support
- various target variable mapping changes
- declare mapper directive support
- omp_get_device_num API addition
- OMPT support
- OMPD support
- OpenMP 5.0 Fortran support (and finish up the remaining missing Fortran 4.5 features)

My short term todo list:

- requires directive other than *atomic* (currently parsed and then ignored); remove or sorry for GCC9?
- inscan modifier (currently parsed in the clause only and then ignored); remove for GCC9?
- add testsuite coverage for ordered and doacross loop with task reductions
- finish up cancelled parallel handling of worksharing reductions
- simd if (perhaps force simdlen 1 for GCC9 or duplicate loop)
- simd nontemporal (try to actually use nontemporal stores)
- host teams runtime (either implement for real for NUMA, or always use 1 team for GCC 9)
- lastprivate conditional (currently parsed and then ignored); remove or sorry for GCC9?
- check what clauses are not handled in tree-nested.c, add testsuite coverage for those
  use
- check auto schedule what we default to, we should default to nonmonotonic
- check omp_init_*lock_with hint state
- testsuite coverage for taskloop construct cancellation
- implement mutexinoutset better than inout in the runtime (GCC 10?)

	Jakub

Comments

Rainer Orth Nov. 8, 2018, 8:39 p.m. UTC | #1
Hi Jakub,

> The OpenMP 5.0 specification, https://www.openmp.org/specifications/ ,
> has been just released a few minutes ago and to celebrate that, I've merged
> gomp-5_0-branch into trunk after bootstrapping/regtesting it on x86_64-linux and
> i686-linux.

this patch series broke the Solaris build:

/vol/gcc/src/hg/trunk/local/libgomp/affinity.c: In function 'gomp_display_affinity_place':
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:145:3: error: unknown type name 'cpu_set_t'
  145 |   cpu_set_t *cpusetp;
      |   ^~~~~~~~~
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:148:5: error: implicit declaration of function 'sprintf' [-Werror=implicit-function-declaration]
  148 |     sprintf (buf, "0-%lu", gomp_available_cpus - 1);
      |     ^~~~~~~

/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:148:5: error: implicit declaration of function 'sprintf' [-Werror=implicit-function-declaration]
  148 |     sprintf (buf, "0-%lu", gomp_available_cpus - 1);
      |     ^~~~~~~
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:148:5: error: incompatible implicit declaration of built-in function 'sprintf' [-Werror]
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:29:1: note: include '<stdio.h>' or provide a declaration of 'sprintf'
   28 | #include "libgomp.h"
  +++ |+#include <stdio.h>
   29 |
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:150:5: error: implicit declaration of function 'strcpy' [-Werror=implicit-function-declaration]
  150 |     strcpy (buf, "0");
      |     ^~~~~~
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:150:5: error: incompatible implicit declaration of built-in function 'strcpy' [-Werror]
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:29:1: note: include '<string.h>' or provide a declaration of 'strcpy'
   28 | #include "libgomp.h"
  +++ |+#include <string.h>
   29 |
/vol/gcc/src/hg/trunk/local/libgomp/affinity.c:151:48: error: implicit declaration of function 'strlen' [-Werror=implicit-function-declaration]
  151 |   gomp_display_string (buffer, size, ret, buf, strlen (buf));
      |                                                ^~~~~~

/vol/gcc/src/hg/trunk/local/libgomp/teams.c: In function 'GOMP_teams_reg':
/vol/gcc/src/hg/trunk/local/libgomp/teams.c:44:19: error: 'INT_MAX' undeclared (first use in this function)
   44 |  = thread_limit > INT_MAX ? UINT_MAX : thread_limit;
      |                   ^~~~~~~
/vol/gcc/src/hg/trunk/local/libgomp/teams.c:29:1: note: 'INT_MAX' is defined in header '<limits.h>'; did you forget to '#include <limits.h>'?
   28 | #include "libgomp.h"
  +++ |+#include <limits.h>
   29 |
/vol/gcc/src/hg/trunk/local/libgomp/teams.c:44:19: note: each undeclared identifier is reported only once for each function it appears in
   44 |  = thread_limit > INT_MAX ? UINT_MAX : thread_limit;
      |                   ^~~~~~~
/vol/gcc/src/hg/trunk/local/libgomp/teams.c:44:29: error: 'UINT_MAX' undeclared (first use in this function)
   44 |  = thread_limit > INT_MAX ? UINT_MAX : thread_limit;
      |                             ^~~~~~~~

The patch below fixes this and allows the build to continue on
i386-pc-solaris2.1[01] and sparc-sun-solaris2.11.  Also built on
x86_64-pc-linux-gnu.

I guess this is obvious?

	Rainer
Jakub Jelinek Nov. 8, 2018, 8:46 p.m. UTC | #2
On Thu, Nov 08, 2018 at 09:39:12PM +0100, Rainer Orth wrote:
> I guess this is obvious?
> 
> 	Rainer
> 
> -- 
> -----------------------------------------------------------------------------
> Rainer Orth, Center for Biotechnology, Bielefeld University
> 
> 
> 2018-11-08  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
> 
> 	* affinity.c: Include <string.h>, <stdio.h>.
> 	(gomp_display_affinity_place): Remove cpusetp.
> 	* teams.c: Include <limits.h>.

Ok, thanks.

	Jakub
Thomas Schwinge Dec. 14, 2018, 8:55 p.m. UTC | #3
Hi Jakub!

On Thu, 8 Nov 2018 18:16:11 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> The OpenMP 5.0 specification, https://www.openmp.org/specifications/ ,
> has been just released a few minutes ago and to celebrate that, I've merged
> gomp-5_0-branch into trunk after bootstrapping/regtesting it on x86_64-linux and
> i686-linux.

In addition to not having tested this with nvptx offloading (where Tom
and you now restored the regressed test cases, thanks!), I can tell that
you also didn't test this with Intel MIC (emulated) offloading.  ;-)

> Because the amount of changes in OpenMP 5.0 is much bigger than in any of the earlier
> releases of the standard, [...]

Oh yes, that's massive!  I immediately thought "poor Jakub" ;-) when I
read a summary of all the new stuff in there.


After <https://gcc.gnu.org/PR87833> 'Intel MIC (emulated) offloading:
"relocation [...] can not be used when making a shared object; recompile
with -fPIC"', yours is now another commit that further broke Intel MIC
(emulated) offloading, but in the past month apparently nobody but me has
run into this (or didn't bother to report it), and I thus again wonder
whether anyone but me is still testing Intel MIC (emulated) offloading?

Anyway, that was easy enough to fix; in r267145 committed to trunk:

commit fbd4f724c13b078755a96a257eabc18ddb83a9cd
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Dec 14 20:41:46 2018 +0000

    Repair liboffloadmic after "(Partial) OpenMP 5.0 support for GCC 9"
    
    ..., which now failed to build, as follows:
    
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        [...]/source-gcc/liboffloadmic/runtime/offload.h:220:12: error: conflicting declaration of C function 'int omp_target_is_present(void*, int)'
          220 | extern int omp_target_is_present(
              |            ^~~~~~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload.h:45,
                         from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        ./../libgomp/omp.h:166:12: note: previous declaration 'int omp_target_is_present(const void*, int)'
          166 | extern int omp_target_is_present (const void *, int) __GOMP_NOTHROW;
              |            ^~~~~~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        [...]/source-gcc/liboffloadmic/runtime/offload.h:236:12: error: conflicting declaration of C function 'int omp_target_memcpy(void*, void*, size_t, size_t, size_t, int, int)'
          236 | extern int omp_target_memcpy(
              |            ^~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload.h:45,
                         from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        ./../libgomp/omp.h:167:12: note: previous declaration 'int omp_target_memcpy(void*, const void*, long unsigned int, long unsigned int, long unsigned int, int, int)'
          167 | extern int omp_target_memcpy (void *, const void *, __SIZE_TYPE__,
              |            ^~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        [...]/source-gcc/liboffloadmic/runtime/offload.h:262:12: error: conflicting declaration of C function 'int omp_target_memcpy_rect(void*, void*, size_t, int, const size_t*, const size_t*, const size_t*, const size_t*, const size_t*, int, int)'
          262 | extern int omp_target_memcpy_rect(
              |            ^~~~~~~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload.h:45,
                         from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        ./../libgomp/omp.h:170:12: note: previous declaration 'int omp_target_memcpy_rect(void*, const void*, long unsigned int, int, const long unsigned int*, const long unsigned int*, const long unsigned int*, const long unsigned int*, const long unsigned int*, int, int)'
          170 | extern int omp_target_memcpy_rect (void *, const void *, __SIZE_TYPE__, int,
              |            ^~~~~~~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        [...]/source-gcc/liboffloadmic/runtime/offload.h:285:12: error: conflicting declaration of C function 'int omp_target_associate_ptr(void*, void*, size_t, size_t, int)'
          285 | extern int omp_target_associate_ptr(
              |            ^~~~~~~~~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload.h:45,
                         from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        ./../libgomp/omp.h:177:12: note: previous declaration 'int omp_target_associate_ptr(const void*, const void*, long unsigned int, long unsigned int, int)'
          177 | extern int omp_target_associate_ptr (const void *, const void *, __SIZE_TYPE__,
              |            ^~~~~~~~~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        [...]/source-gcc/liboffloadmic/runtime/offload.h:299:12: error: conflicting declaration of C function 'int omp_target_disassociate_ptr(void*, int)'
          299 | extern int omp_target_disassociate_ptr(
              |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
        In file included from [...]/source-gcc/liboffloadmic/runtime/offload.h:45,
                         from [...]/source-gcc/liboffloadmic/runtime/offload_common.h:43,
                         from [...]/source-gcc/liboffloadmic/runtime/dv_util.cpp:31:
        ./../libgomp/omp.h:179:12: note: previous declaration 'int omp_target_disassociate_ptr(const void*, int)'
          179 | extern int omp_target_disassociate_ptr (const void *, int) __GOMP_NOTHROW;
              |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~
        Makefile:904: recipe for target 'liboffloadmic_target_la-dv_util.lo' failed
        make[3]: *** [liboffloadmic_target_la-dv_util.lo] Error 1
        make[3]: Leaving directory '[...]/build-gcc-offload-x86_64-intelmicemul-linux-gnu/x86_64-intelmicemul-linux-gnu/liboffloadmic'
        Makefile:1031: recipe for target 'all-recursive' failed
        make[2]: *** [all-recursive] Error 1
        make[2]: Leaving directory '[...]/build-gcc-offload-x86_64-intelmicemul-linux-gnu/x86_64-intelmicemul-linux-gnu/liboffloadmic'
        Makefile:12707: recipe for target 'all-target-liboffloadmic' failed
        make[1]: *** [all-target-liboffloadmic] Error 2
        make[1]: Leaving directory '[...]/build-gcc-offload-x86_64-intelmicemul-linux-gnu'
        Makefile:941: recipe for target 'all' failed
        make: *** [all] Error 2
    
            liboffloadmic/
            * runtime/offload.h (omp_target_is_present, omp_target_memcpy)
            (omp_target_memcpy_rect, omp_target_associate_ptr)
            (omp_target_disassociate_ptr): Adjust to libgomp changes.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@267145 138bc75d-0d04-0410-961f-82ee72b054a4
---
 liboffloadmic/ChangeLog         |  6 ++++++
 liboffloadmic/runtime/offload.h | 12 ++++++------
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git liboffloadmic/ChangeLog liboffloadmic/ChangeLog
index 701cdff074ac..8e4dc3747141 100644
--- liboffloadmic/ChangeLog
+++ liboffloadmic/ChangeLog
@@ -1,3 +1,9 @@
+2018-12-14  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* runtime/offload.h (omp_target_is_present, omp_target_memcpy)
+	(omp_target_memcpy_rect, omp_target_associate_ptr)
+	(omp_target_disassociate_ptr): Adjust to libgomp changes.
+
 2018-10-31  Joseph Myers  <joseph@codesourcery.com>
 
 	PR bootstrap/82856
diff --git liboffloadmic/runtime/offload.h liboffloadmic/runtime/offload.h
index b12af3442a56..4a329ba0e560 100644
--- liboffloadmic/runtime/offload.h
+++ liboffloadmic/runtime/offload.h
@@ -218,7 +218,7 @@ extern void omp_target_free(
     \return            true if storage is found, false otherwise.
 */
 extern int omp_target_is_present(
-    void *ptr,
+    const void *ptr,
     int device_num
 ) __GOMP_NOTHROW;
 
@@ -235,7 +235,7 @@ extern int omp_target_is_present(
 */
 extern int omp_target_memcpy(
     void   *dst, 
-    void   *src, 
+    const void *src,
     size_t  length, 
     size_t  dst_offset, 
     size_t  src_offset, 
@@ -261,7 +261,7 @@ extern int omp_target_memcpy(
 */
 extern int omp_target_memcpy_rect(
     void         *dst,
-    void         *src,
+    const void   *src,
     size_t        element_size,
     int           num_dims,
     const size_t *volume,
@@ -283,8 +283,8 @@ extern int omp_target_memcpy_rect(
     \return               0 on success, 1 otherwise.
 */
 extern int omp_target_associate_ptr(
-    void   *host_ptr, 
-    void   *device_ptr,
+    const void *host_ptr,
+    const void *device_ptr,
     size_t  size,
     size_t  device_offset,
     int     device_num
@@ -297,7 +297,7 @@ extern int omp_target_associate_ptr(
     \return            0 on success, 1 otherwise.
 */
 extern int omp_target_disassociate_ptr(
-    void   *host_ptr,
+    const void *host_ptr,
     int     device_num
 ) __GOMP_NOTHROW;
 


Grüße
 Thomas
Jakub Jelinek Dec. 14, 2018, 9:03 p.m. UTC | #4
On Fri, Dec 14, 2018 at 09:55:51PM +0100, Thomas Schwinge wrote:
> Anyway, that was easy enough to fix; in r267145 committed to trunk:

>             liboffloadmic/
>             * runtime/offload.h (omp_target_is_present, omp_target_memcpy)
>             (omp_target_memcpy_rect, omp_target_associate_ptr)
>             (omp_target_disassociate_ptr): Adjust to libgomp changes.

Thanks; indeed, I wasn't testing the OpenMP 5.0 patchset with offloading
mainly because there weren't too many offloading related changes so far
(most of them waiting for GCC 10).

	Jakub
Kwok Cheung Yeung Nov. 20, 2020, 4:41 p.m. UTC | #5
Hello

> New OpenMP 5.0 features that won't be available in GCC 9, are planned for GCC 10
> or later versions as time permits:
> 
...
> - nested declare target support

You said in an email two years ago that nested declare target was not supported 
yet. I do not see any patches that claim to implement this since then, but when 
I ran a quick test with a trunk build:

#pragma omp declare target
   #pragma omp declare target
     int foo() { return 1; }
   #pragma omp end declare target
   int bar() { return 2; }
#pragma omp end declare target

This compiles and appears to do the right thing:

__attribute__((omp declare target, omp declare target block))
foo ()
...

__attribute__((omp declare target, omp declare target block))
bar ()
...

Looking at the C parser:

static void
c_parser_omp_declare_target (c_parser *parser)
{
   ...
   else
     {
       c_parser_skip_to_pragma_eol (parser);
       current_omp_declare_target_attribute++;
       return;
     }

static void
c_parser_omp_end_declare_target (c_parser *parser)
{
   ...
     current_omp_declare_target_attribute--;
}

It looks like this was written to handle nesting to begin with (since at least 
2013) by making current_omp_declare_target_attribute (which effectively tracks 
the nesting level) an integer. Is there anything that is currently missing for 
nested declare target support?

Thanks

Kwok
Jakub Jelinek Dec. 8, 2020, 4:45 p.m. UTC | #6
On Fri, Nov 20, 2020 at 04:41:15PM +0000, Kwok Cheung Yeung wrote:
> Hello
> 
> > New OpenMP 5.0 features that won't be available in GCC 9, are planned for GCC 10
> > or later versions as time permits:
> > 
> ...
> > - nested declare target support
> 
> You said in an email two years ago that nested declare target was not
> supported yet. I do not see any patches that claim to implement this since
> then, but when I ran a quick test with a trunk build:
> 
> #pragma omp declare target
>   #pragma omp declare target
>     int foo() { return 1; }
>   #pragma omp end declare target
>   int bar() { return 2; }
> #pragma omp end declare target

> It looks like this was written to handle nesting to begin with (since at
> least 2013) by making current_omp_declare_target_attribute (which
> effectively tracks the nesting level) an integer. Is there anything that is
> currently missing for nested declare target support?

We used to reject omp declare target with clauses in between declare target
without clauses, but that restriction has been lifted, so I don't know what
is missing, perhaps just add testcases that aren't covered in the testsuite
already.  I'm a little bit worried about the interaction between declare
target with nohost vs. normal one etc.
But to answer the question, I don't remember anymore why it was on the
unfinished list.

	Jakub