[OpenMP] Always apply target declarations to canonical definitions

This patch changes the handling of OpenMP to add the device attributes
to the canonical definitions when we encounter a non-canonical
definition. Previously, the following code would not work because it
would find the non-canonical definition first which would then not be
used anywhere else.

```
int x;
extern int x;
```

This patch now adds the attribute to both of them. This allows us to
perform the following operation if, for example, there were an
implementation of `stderr` on the device.

```
#include <stdio.h>

// List of libc symbols supported on the device.
extern FILE *stderr;
```

Unfortunately I cannot think of an equivalent solution to HIP / CUDA
device declarations as those are done with simple attributes. Attributes
themselves cannot be used to affect a definition once its canonical
definition has already been seen. Some help on that front would be
appreciated.

Fixes https://github.com/llvm/llvm-project/issues/63355

Reviewed By: ABataev

Differential Revision: https://reviews.llvm.org/D153369
This commit is contained in:
Joseph Huber 2023-06-20 12:03:48 -05:00
parent 3254623d73
commit 1d699bf266
2 changed files with 23 additions and 8 deletions

View File

@ -151,14 +151,16 @@ void OMPDeclareTargetDeclAttr::printPrettyPragma(
std::optional<OMPDeclareTargetDeclAttr *>
OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) {
if (!VD->hasAttrs())
if (llvm::all_of(VD->redecls(), [](const Decl *D) { return !D->hasAttrs(); }))
return std::nullopt;
unsigned Level = 0;
OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
for (auto *Attr : VD->specific_attrs<OMPDeclareTargetDeclAttr>()) {
if (Level <= Attr->getLevel()) {
Level = Attr->getLevel();
FoundAttr = Attr;
for (const Decl *D : VD->redecls()) {
for (auto *Attr : D->specific_attrs<OMPDeclareTargetDeclAttr>()) {
if (Level <= Attr->getLevel()) {
Level = Attr->getLevel();
FoundAttr = Attr;
}
}
}
if (FoundAttr)

View File

@ -27,11 +27,13 @@
// CHECK-DAG: Bake
// CHECK-NOT: @{{hhh|ggg|fff|eee}} =
// CHECK-DAG: @flag = protected global i8 undef,
// CHECK-DAG: @dx = {{protected | }}global i32 0,
// CHECK-DAG: @dy = {{protected | }}global i32 0,
// CHECK-DAG: @aaa = external global i32,
// CHECK-DAG: @bbb ={{ protected | }}global i32 0,
// CHECK-DAG: @bbb = {{protected | }}global i32 0,
// CHECK-DAG: weak constant %struct.__tgt_offload_entry { ptr @bbb,
// CHECK-DAG: @ccc = external global i32,
// CHECK-DAG: @ddd ={{ protected | }}global i32 0,
// CHECK-DAG: @ddd = {{protected | }}global i32 0,
// CHECK-DAG: @hhh_decl_tgt_ref_ptr = weak global ptr null
// CHECK-DAG: @ggg_decl_tgt_ref_ptr = weak global ptr null
// CHECK-DAG: @fff_decl_tgt_ref_ptr = weak global ptr null
@ -51,10 +53,21 @@
// CHECK-DAG: define {{.*}}i32 @{{.*}}{{foo|bar|baz2|baz3|FA|f_method}}{{.*}}()
// CHECK-DAG: define {{.*}}void @{{.*}}TemplateClass{{.*}}(ptr {{[^,]*}} %{{.*}})
// CHECK-DAG: define {{.*}}i32 @{{.*}}TemplateClass{{.*}}f_method{{.*}}(ptr {{[^,]*}} %{{.*}})
// CHECK-DAG: define {{.*}}void @__omp_offloading_{{.*}}_globals_l[[@LINE+78]]_ctor()
// CHECK-DAG: define {{.*}}void @__omp_offloading_{{.*}}_globals_l[[@LINE+89]]_ctor()
#ifndef HEADER
#define HEADER
int dx = 0;
extern int dx;
#pragma omp declare target to(dx)
int dy = 0;
#pragma omp begin declare target
extern int dy;
#pragma omp end declare target
#pragma omp declare target
bool flag [[clang::loader_uninitialized]];
extern int bbb;