diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -10166,6 +10166,13 @@ std::optional Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); + + // If this is an 'extern' declaration we defer to the canonical definition and + // do not emit an offloading entry. + if (Res && *Res != OMPDeclareTargetDeclAttr::MT_Link && + VD->hasExternalStorage()) + return; + if (!Res) { if (CGM.getLangOpts().OpenMPIsTargetDevice) { // Register non-target variables being emitted in device code (debug info diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3605,6 +3605,13 @@ // Emit declaration of the must-be-emitted declare target variable. if (std::optional Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) { + + // If this variable has external storage and doesn't require special + // link handling we defer to its canonical definition. + if (VD->hasExternalStorage() && + Res != OMPDeclareTargetDeclAttr::MT_Link) + return; + bool UnifiedMemoryEnabled = getOpenMPRuntime().hasRequiresUnifiedSharedMemory(); if ((*Res == OMPDeclareTargetDeclAttr::MT_To || diff --git a/clang/test/OpenMP/declare_target_codegen.cpp b/clang/test/OpenMP/declare_target_codegen.cpp --- a/clang/test/OpenMP/declare_target_codegen.cpp +++ b/clang/test/OpenMP/declare_target_codegen.cpp @@ -29,7 +29,6 @@ // 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: weak constant %struct.__tgt_offload_entry { ptr @bbb, // CHECK-DAG: @ccc = external global i32, @@ -80,7 +79,7 @@ extern int aaa; int bbb = 0; extern int ccc; -int ddd = 0; +int ddd = ccc; #pragma omp end declare target #pragma omp declare target @@ -260,8 +259,6 @@ // CHECK-NOT: define {{.*}}{{baz1|baz4|maini1|Base|virtual_}} -// CHECK-DAG: !{i32 1, !"aaa", i32 0, i32 {{[0-9]+}}} -// CHECK-DAG: !{i32 1, !"ccc", i32 0, i32 {{[0-9]+}}} // CHECK-DAG: !{{{.+}}virtual_foo #ifdef OMP5 diff --git a/openmp/libomptarget/test/offloading/extern.c b/openmp/libomptarget/test/offloading/extern.c new file mode 100644 --- /dev/null +++ b/openmp/libomptarget/test/offloading/extern.c @@ -0,0 +1,27 @@ +// RUN: %libomptarget-compile-generic -DVAR -c -o %t.o +// RUN: %libomptarget-compile-generic %t.o && %libomptarget-run-generic | %fcheck-generic + +#ifdef VAR +int x = 1; +#else +#include +#include +extern int x; + +int main() { + int value = 0; +#pragma omp target map(from : value) + value = x; + assert(value == 1); + + x = 999; +#pragma omp target update to(x) + +#pragma omp target map(from : value) + value = x; + assert(value == 999); + + // CHECK: PASS + printf ("PASS\n"); +} +#endif