Hello world, hi Chung-Lin,

first, can you add 'PR middle-end/122205' to your changelog?
that's about what you implemented ( https://gcc.gnu.org/PR122205 )


Chung-Lin Tang wrote:

this implements 'link' clause behavior for 'enter' maps, when
detected that 'requires self_maps' is in effect.

We should to do the same with 'requires unified_shared_memory'.

For 'self_maps', the implementation is required that the device
and the host variable access the same memory. For 'unified_shared_memory',
it is left open whether explicit map clauses have an effect or not.
However, we ignore all map operations (aka as self mapping) with
either requirement, which leads to wrong code for:

#pragma omp requires unified_shared_memory // or 'self_maps' before your patch

int var;
#pragma omp declare target enter(var)

int main() {
  var = 5;
  #pragma omp target map(always, tofrom: var)
    var++;
  __builtin_printf ("%d\n", var); // should print 6, might print 1 or garbage
}


This basically does it in the front-ends, changing the tagged
attribute to "target link" under the supposed right conditions.

This fails for:

#pragma omp requires self_maps

#pragma omp begin declare target
void f() { }
#pragma omp declare target enter(f) device_type(nohost)
#pragma omp end declare target

with the error message:

foo.c:5:33: error: ‘f’ specified both in declare target ‘link’ and ‘enter’ 
clauses
    5 | #pragma omp declare target enter(f) device_type(nohost)

* * *

Actually: This one is odd in multiple ways, because for *functions* it
shouldn't the clause to 'link'!

* * *

On the other hand, 'begin declare target' doesn't seem to work with variables
either - while it compiles ...

#pragma omp requires self_maps

#pragma omp begin declare target
static int val;
int f() { return val; }
#pragma omp end declare target

int main() {
  int res = 0;
  val = 41;

  #pragma omp target map(from: res)
    res = f();
  __builtin_printf ("val = %d\n", res);
}

... it gives here 0 instead of the expected 41 as result.

* * *

The following also fails (device-side variable not created) - but
it is unrelated to your patch → https://gcc.gnu.org/PR126255

program main
  implicit none
  !$omp requires self_maps
  integer :: var, res
  var = 5
  call test
  !$omp target
    res = f()
  !$omp end target
contains
  subroutine test
    !$omp declare target enter(var)
  end
  integer function f()
    f = var
  end
end

* * *

I noticed that the following code is currently rejected with
  foo.c:3:12: error: ‘init’ specified both in declare target ‘link’ and 
implicitly in ‘to’ clauses
but it is no longer with you patch:

#pragma omp requires self_maps

static int init;
#pragma omp declare target link(init)
static int *val = &init;
#pragma omp declare target enter(val)

#pragma omp begin declare target
int f() { init++; return *val; }
#pragma omp end declare target

int main() {
  int res = 0;
  init = 42;

  #pragma omp target map(from: res)
    res = f();
  __builtin_printf ("val = %d\n", res);
}


Expected: As 'init' is implicitly 'enter', it should be rejected
as there is an explicit 'link' clause as well.

* * *

The reverse is invalid as well, but not diagnosed, either
→  https://gcc.gnu.org/PR126256
but that's unrelated to your patch.

* * *

The following code works with manually using 'link' but
fails with 'enter':

implicit none
!$omp requires self_maps

integer :: x = 7
common /com/ x
! !$omp declare target link(/com/) ! -- works: prints 8
!$omp declare target enter(/com/)  ! -- fails: prints 7

x = 8

!$omp target
  print *, f()
!$omp end target
contains
  integer function f()
    f = x
  end
end


* * *

Side remark: For the following code, we should not change
'enter' to 'link' - as the variable is supposed to only
exist on the device (likewise for 'host' but there is does
not really matter):


#pragma omp requires self_maps

static int val = 5;
#pragma omp declare target enter(val) device_type(nohost)

#pragma omp begin declare target device_type(nohost)
int f() { return omp_is_initial_device() ? 99 : val; }
#pragma omp end declare target

int main() {
  int res = 0;

  #pragma omp target map(from: res) // device_type(nohost)
    res = f();
  __builtin_printf ("val = %d\n", res);
}

This is currently not run-time detectable but the performance
is definitely better when accessing the device variable and
not the host variable.
(It starts to matter when we stop outputting nohost variables
and functions on the host.)

Note: 'device_type([no]host)' on target is not yet implemented;
the example works around this by using the 'omp_is_initial_device'
builtin that is compile-time evaluated.

* * *

Tobias,
who still has to read through the actual patch.

Reply via email to