diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11324,6 +11324,11 @@ void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, SourceLocation IdLoc = SourceLocation()); + + /// Adds OMPDeclareTargetDeclAttr to referenced variables in declare target + /// directive. + void ActOnOpenMPDeclareTargetInitializer(Decl *D); + /// Finishes analysis of the deferred functions calls that may be declared as /// host/nohost during device/host compilation. void finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -14476,6 +14476,12 @@ for (unsigned i = 0, e = Group.size(); i != e; ++i) { if (Decl *D = Group[i]) { + // Check if the Decl has been declared in '#pragma omp declare target' + // directive and has static storage duration. + if (auto *VD = dyn_cast(D); + LangOpts.OpenMP && VD && VD->hasAttr() && + VD->hasGlobalStorage()) + ActOnOpenMPDeclareTargetInitializer(D); // For declarators, there are some additional syntactic-ish checks we need // to perform. if (auto *DD = dyn_cast(D)) { diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -23100,6 +23100,55 @@ checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D); } +/// This class visits every VarDecl that the initializer references and adds +/// OMPDeclareTargetDeclAttr to each of them. +class GlobalDeclRefChecker final + : public StmtVisitor { + SmallVector DeclVector; + Attr *A; + +public: + /// A StmtVisitor class function that visits all DeclRefExpr and adds + /// OMPDeclareTargetDeclAttr to them. + void VisitDeclRefExpr(DeclRefExpr *Node) { + if (auto *VD = dyn_cast(Node->getDecl())) { + VD->addAttr(A); + DeclVector.push_back(VD); + } + } + /// A function that iterates across each of the Expr's children. + void VisitExpr(Expr *Ex) { + for (auto *Child : Ex->children()) { + Visit(Child); + } + } + /// A function that keeps a record of all the Decls that are variables, has + /// OMPDeclareTargetDeclAttr, and has global storage in the DeclVector. Pop + /// each Decl one at a time and use the inherited 'visit' functions to look + /// for DeclRefExpr. + void declareTargetInitializer(Decl *TD) { + A = TD->getAttr(); + DeclVector.push_back(cast(TD)); + while (!DeclVector.empty()) { + VarDecl *TargetVarDecl = DeclVector.pop_back_val(); + if (TargetVarDecl->hasAttr() && + TargetVarDecl->hasInit() && TargetVarDecl->hasGlobalStorage()) { + if (Expr *Ex = TargetVarDecl->getInit()) + Visit(Ex); + } + } + } +}; + +/// Adding OMPDeclareTargetDeclAttr to variables with static storage +/// duration that are referenced in the initializer expression list of +/// variables with static storage duration in declare target directive. +void Sema::ActOnOpenMPDeclareTargetInitializer(Decl *TargetDecl) { + GlobalDeclRefChecker Checker; + if (auto *TargetVarDecl = dyn_cast_or_null(TargetDecl)) + Checker.declareTargetInitializer(TargetDecl); +} + OMPClause *Sema::ActOnOpenMPToClause( ArrayRef MotionModifiers, ArrayRef MotionModifiersLoc, diff --git a/clang/test/OpenMP/declare_target_messages.cpp b/clang/test/OpenMP/declare_target_messages.cpp --- a/clang/test/OpenMP/declare_target_messages.cpp +++ b/clang/test/OpenMP/declare_target_messages.cpp @@ -233,6 +233,42 @@ #pragma omp declare target to(MultiDevTy) device_type(host) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-error {{'device_type(host)' does not match previously specified 'device_type(any)' for the same declaration}} omp51-error {{'device_type(host)' does not match previously specified 'device_type(any)' for the same declaration}} omp52-error {{unexpected 'to' clause, use 'enter' instead}} omp52-error {{expected at least one 'enter', 'link' or 'indirect' clause}} #pragma omp declare target to(MultiDevTy) device_type(nohost) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-error {{'device_type(nohost)' does not match previously specified 'device_type(any)' for the same declaration}} // omp51-error {{'device_type(nohost)' does not match previously specified 'device_type(any)' for the same declaration}} omp52-error {{unexpected 'to' clause, use 'enter' instead}} omp52-error {{expected at least one 'enter', 'link' or 'indirect' clause}} +static int variable = 100; //expected-warning {{declaration is not declared in any declare target region}} +static float variable1 = 200; +static float variable2 = variable1; //expected-warning {{declaration is not declared in any declare target region}} + +static int var = 1; //expected-warning {{declaration is not declared in any declare target region}} + +static int var1 = 10; +static int *var2 = &var1; +static int **ptr1 = &var2; //expected-warning {{declaration is not declared in any declare target region}} + +int arr[2] = {1,2}; +int (*arrptr)[2] = &arr; //expected-warning {{declaration is not declared in any declare target region}} + +class declare{ + public: int x; + void print(); +}; +declare obj1; +declare *obj2 = &obj1; //expected-warning {{declaration is not declared in any declare target region}} + +struct target{ + int x; + void print(); +}; +static target S; //expected-warning {{declaration is not declared in any declare target region}} + +#pragma omp declare target +int target_var = variable; //expected-note {{used here}} +float target_var1 = variable2; //expected-note {{used here}} +int *ptr = &var; //expected-note {{used here}} +int ***ptr2 = &ptr1; //expected-note {{used here}} +int (**ptr3)[2] = &arrptr; //expected-note {{used here}} +declare **obj3 = &obj2; //expected-note {{used here}} +target *S1 = &S; //expected-note {{used here}} +#pragma omp end declare target + #if TESTENDINC #include "unterminated_declare_target_include.h" #elif TESTEND diff --git a/clang/test/OpenMP/declare_target_variables_ast_print.cpp b/clang/test/OpenMP/declare_target_variables_ast_print.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/declare_target_variables_ast_print.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -w -verify -fopenmp -I %S/Inputs -ast-print %s | FileCheck %s --check-prefix=CHECK +// expected-no-diagnostics + +static int variable = 100; +static float variable1 = 200; +static float variable2 = variable1; + +static int var = 1; + +static int var1 = 10; +static int *var2 = &var1; +static int **ptr1 = &var2; + +int arr[2] = {1,2}; +int (*arrptr)[2] = &arr; + +class declare{ + public: int x; + void print(); +}; +declare obj1; +declare *obj2 = &obj1; + +struct target{ + int x; + void print(); +}; +static target S; + +#pragma omp declare target +int target_var = variable; +float target_var1 = variable2; +int *ptr = &var; +int ***ptr2 = &ptr1; +int (**ptr3)[2] = &arrptr; +declare **obj3 = &obj2; +target *S1 = &S; +#pragma omp end declare target +// CHECK: #pragma omp declare target +// CHECK-NEXT: static int variable = 100; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static float variable1 = 200; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static float variable2 = variable1; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK: #pragma omp declare target +// CHECK-NEXT: static int var = 1; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static int var1 = 10; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static int *var2 = &var1; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static int **ptr1 = &var2; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int arr[2] = {1, 2}; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int (*arrptr)[2] = &arr; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: class declare { +// CHECK-NEXT: public: +// CHECK-NEXT: int x; +// CHECK-NEXT: void print(); +// CHECK-NEXT: }; +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: declare obj1; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: declare *obj2 = &obj1; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: struct target { +// CHECK-NEXT: int x; +// CHECK-NEXT: void print(); +// CHECK-NEXT: }; +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static target S; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int target_var = variable; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: float target_var1 = variable2; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int *ptr = &var; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int ***ptr2 = &ptr1; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int (**ptr3)[2] = &arrptr; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: declare **obj3 = &obj2; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: target *S1 = &S; +// CHECK-NEXT: #pragma omp end declare target + diff --git a/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp b/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp --- a/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp +++ b/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp @@ -95,7 +95,7 @@ int (*D)() = C; // expected-note {{used here}} // host-note@-1 {{used here}} #pragma omp end declare target -int foobar3() { throw 1; } +int foobar3() { throw 1; } // expected-error {{cannot use 'throw' with exceptions disabled}} // Check no infinite recursion in deferred diagnostic emitter. long E = (long)&E;