Bug 100059

Summary: [OpenMP] wrong code with 'declare target link' and a scalar variable
Product: gcc Reporter: Tobias Burnus <burnus>
Component: otherAssignee: Thomas Schwinge <tschwinge>
Status: RESOLVED FIXED    
Severity: normal CC: jakub, tschwinge, vries
Priority: P3 Keywords: openmp, wrong-code
Version: 11.0   
Target Milestone: ---   
See Also: https://github.com/MentorEmbedded/nvptx-tools/pull/29
Host: Target: nvptx-none
Build: Known to work:
Known to fail: Last reconfirmed: 2021-04-13 00:00:00
Attachments: Testcase, compile with 'gcc -fopenmp' with an (nvptx) offloading enabled compiler

Description Tobias Burnus 2021-04-13 08:58:51 UTC
Created attachment 50578 [details]
Testcase, compile with 'gcc -fopenmp' with an (nvptx) offloading enabled compiler

The attached testcase has four global vars:
  int a[N], b[N], c[N];
  int i = 0;

which are used with:

  #pragma omp declare target link(a,c,b,i)  

and

  #pragma omp target map(to: i) map(tofrom: a, b, c) 
    update();

After the call, the one array is not updated but has the previous host value:
* For 'declare target link(a,c,b,i)': not updated array is 'b'
* For 'declare target link(a,b,c,i)': not updated array is 'c'

Namely, the testcase shows:
i=5: A=5, B=6, C=7    // Original host value
i=5: A=6, B=6, C=10   // target call to 'update': 'B' is not updated
i=5: A=7, B=8, C=13   // host update, OK


Additionally, when using 'for (int i' in 'update': The error only shows up if there is 'i'
And it occurs for the item before 'i', namely:
  link(a,c,b,i) → 'b' is wrong
  link(a,c,i,b) → 'c' is wrong


The issue occurs with nvptx. It works without offloading and I think it works with GCN (did not show up in the test logs, but I have not manually verified).
Comment 1 Tobias Burnus 2021-04-13 13:16:32 UTC
For
  #pragma omp declare target link(a,c,b,i)
the vars are walked in reverse order (= in normal order of 'offload_vars'):

* In a.xnvptx-none.mkoffload.s:
------------
//:FUNC_MAP "main$_omp_fn$0"
//:VAR_MAP "i$linkptr"


// BEGIN GLOBAL VAR DEF: i$linkptr
        .visible .global .align 8 .u64 i$linkptr[1];
//:VAR_MAP "b$linkptr"

// BEGIN GLOBAL VAR DEF: b$linkptr
        .visible .global .align 8 .u64 b$linkptr[1];
//:VAR_MAP "c$linkptr"

// BEGIN GLOBAL VAR DEF: c$linkptr
        .visible .global .align 8 .u64 c$linkptr[1];
//:VAR_MAP "a$linkptr"

// BEGIN GLOBAL VAR DEF: a$linkptr
        .visible .global .align 8 .u64 a$linkptr[1];

// BEGIN GLOBAL FUNCTION DECL: gomp_nvptx_main
------------

So far so good. However, after:
  nvptx-none/bin/as -m sm_35 -o ./a.xnvptx-none.mkoffload.o ./a.xnvptx-none.mkoffload.s

the 'a.xnvptx-none.mkoffload.o' contains:

----------------
// BEGIN GLOBAL VAR DECL: __nvptx_uni
.extern .shared .u32 __nvptx_uni[32];
//:VAR_MAP "b$linkptr"
// BEGIN GLOBAL VAR DEF: b$linkptr
.visible .global .align 8 .u64 b$linkptr[1];
//:FUNC_MAP "main$_omp_fn$0"
//:VAR_MAP "i$linkptr"
// BEGIN GLOBAL VAR DEF: i$linkptr
.visible .global .align 8 .u64 i$linkptr[1];
//:VAR_MAP "c$linkptr"
// BEGIN GLOBAL VAR DEF: c$linkptr
.visible .global .align 8 .u64 c$linkptr[1];
//:VAR_MAP "a$linkptr"
// BEGIN GLOBAL VAR DEF: a$linkptr
.visible .global .align 8 .u64 a$linkptr[1];
// BEGIN GLOBAL FUNCTION DEF: update
----------------

Namely: 'b' and 'i' swapped the order!

The problem seems to be the misplaced:
  //:FUNC_MAP "main$_omp_fn$0"
Comment 2 Tobias Burnus 2021-04-13 13:37:20 UTC
Probably a read herring as I still get for a.xnvptx-none.c:

static const char *const var_mappings[] = {
        "b$linkptr",
        "i$linkptr",
        "c$linkptr",
        "a$linkptr"
};
Comment 3 Tobias Burnus 2021-04-13 14:11:00 UTC
With GCN it does work:
 i=5: A=5, B=6, C=7
 i=5: A=6, B=8, C=10
 i=5: A=7, B=10, C=13

And the follow testcase prints:
* with nvptx:
  42, 5, 0, 0
* with amdgcn:
  5, 42, 43, 44

This something must be reversed ...
//-----------------------------------------------
int i = 0, a[3];

void update () { 
  i = 5; a[0] = 42; a[1] = 43; a[2] = 44;
}

#pragma omp declare target link(i,a)
#pragma omp declare target to(update)  

int main () {
  #pragma omp target map(from: i, a)
    update();
__builtin_printf("%d, %d, %d, %d\n", i,a[0],a[1],a[2]);
  return 0;
}
Comment 4 Tobias Burnus 2021-04-13 16:39:42 UTC
That's in issue with how the nvptx pseudoassembler re-outputs the assembler, which reorders the symbols – such that the order in var_mappings is wrong (i.e. differs from the order on the host).

(Order is based on traversing the htab – I wonder why this did not show up before?)  

See ISSUE DESCRIPTION and SOLUTION (PATCH) at
https://github.com/MentorEmbedded/nvptx-tools/pull/29
Comment 5 Tobias Burnus 2022-03-29 10:23:27 UTC
Another example for this is https://github.com/clang-ykt/omptests 's t-same-name-definitions which has the same issue + is fixed by the pull request for nvptx-tools.
Comment 6 Thomas Schwinge 2023-09-04 09:37:56 UTC
(In reply to Tobias Burnus from comment #4)
> https://github.com/MentorEmbedded/nvptx-tools/pull/29

This is now finally incorporated, sorry for the (long...) delay.

Are you going to push the GCC-level test case (submitted in this PR), or want me to?  For nvptx offloading, it'll FAIL its execution test until nvptx-tools updated, but that's OK in my opinion.
Comment 7 Thomas Schwinge 2023-09-04 12:57:44 UTC
commit r14-3650-gfe0f9e09413047484441468b05288412760d8a09 "Add 'libgomp.c-c++-common/pr100059-1.c'"