Skip to content

Commit dd4c838

Browse files
committed
[OpenMP] Allow data members in interop init/use/destroy clauses
Previously a diagnostic was given if the expression was not strictly a DeclRef. Now also allow use of data members inside member functions. Differential Revision: https://reviews.llvm.org/D131222
1 parent c6c5944 commit dd4c838

File tree

5 files changed

+272
-31
lines changed

5 files changed

+272
-31
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10387,6 +10387,9 @@ def err_omp_unexpected_clause_value : Error<
1038710387
"expected %0 in OpenMP clause '%1'">;
1038810388
def err_omp_expected_var_name_member_expr : Error<
1038910389
"expected variable name%select{| or data member of current class}0">;
10390+
def err_omp_expected_var_name_member_expr_with_type : Error<
10391+
"expected variable%select{| or static data member|, static data member, "
10392+
"or non-static data member of current class}0 of type '%1'">;
1039010393
def err_omp_expected_var_name_member_expr_or_array_item : Error<
1039110394
"expected variable name%select{|, data member of current class}0, array element or array section">;
1039210395
def err_omp_expected_addressable_lvalue_or_array_item : Error<

clang/lib/Sema/SemaOpenMP.cpp

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2718,7 +2718,8 @@ void Sema::EndOpenMPClause() {
27182718

27192719
static std::pair<ValueDecl *, bool>
27202720
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
2721-
SourceRange &ERange, bool AllowArraySection = false);
2721+
SourceRange &ERange, bool AllowArraySection = false,
2722+
StringRef DiagType = "");
27222723

27232724
/// Check consistency of the reduction clauses.
27242725
static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
@@ -5279,7 +5280,8 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
52795280
static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
52805281
SourceLocation &ELoc,
52815282
SourceRange &ERange,
5282-
bool AllowArraySection) {
5283+
bool AllowArraySection,
5284+
StringRef DiagType) {
52835285
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
52845286
RefExpr->containsUnexpandedParameterPack())
52855287
return std::make_pair(nullptr, true);
@@ -5324,6 +5326,12 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
53245326
if (IsArrayExpr != NoArrayExpr) {
53255327
S.Diag(ELoc, diag::err_omp_expected_base_var_name)
53265328
<< IsArrayExpr << ERange;
5329+
} else if (!DiagType.empty()) {
5330+
unsigned DiagSelect = S.getLangOpts().CPlusPlus
5331+
? (S.getCurrentThisType().isNull() ? 1 : 2)
5332+
: 0;
5333+
S.Diag(ELoc, diag::err_omp_expected_var_name_member_expr_with_type)
5334+
<< DiagSelect << DiagType << ERange;
53275335
} else {
53285336
S.Diag(ELoc,
53295337
AllowArraySection
@@ -17249,32 +17257,28 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
1724917257
// OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
1725017258
// Each interop-var may be specified for at most one action-clause of each
1725117259
// interop construct.
17252-
llvm::SmallPtrSet<const VarDecl *, 4> InteropVars;
17253-
for (const OMPClause *C : Clauses) {
17260+
llvm::SmallPtrSet<const ValueDecl *, 4> InteropVars;
17261+
for (OMPClause *C : Clauses) {
1725417262
OpenMPClauseKind ClauseKind = C->getClauseKind();
17255-
const DeclRefExpr *DRE = nullptr;
17256-
SourceLocation VarLoc;
17263+
std::pair<ValueDecl *, bool> DeclResult;
17264+
SourceLocation ELoc;
17265+
SourceRange ERange;
1725717266

1725817267
if (ClauseKind == OMPC_init) {
17259-
const auto *IC = cast<OMPInitClause>(C);
17260-
VarLoc = IC->getVarLoc();
17261-
DRE = dyn_cast_or_null<DeclRefExpr>(IC->getInteropVar());
17268+
auto *E = cast<OMPInitClause>(C)->getInteropVar();
17269+
DeclResult = getPrivateItem(*this, E, ELoc, ERange);
1726217270
} else if (ClauseKind == OMPC_use) {
17263-
const auto *UC = cast<OMPUseClause>(C);
17264-
VarLoc = UC->getVarLoc();
17265-
DRE = dyn_cast_or_null<DeclRefExpr>(UC->getInteropVar());
17271+
auto *E = cast<OMPUseClause>(C)->getInteropVar();
17272+
DeclResult = getPrivateItem(*this, E, ELoc, ERange);
1726617273
} else if (ClauseKind == OMPC_destroy) {
17267-
const auto *DC = cast<OMPDestroyClause>(C);
17268-
VarLoc = DC->getVarLoc();
17269-
DRE = dyn_cast_or_null<DeclRefExpr>(DC->getInteropVar());
17274+
auto *E = cast<OMPDestroyClause>(C)->getInteropVar();
17275+
DeclResult = getPrivateItem(*this, E, ELoc, ERange);
1727017276
}
1727117277

17272-
if (!DRE)
17273-
continue;
17274-
17275-
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
17276-
if (!InteropVars.insert(VD->getCanonicalDecl()).second) {
17277-
Diag(VarLoc, diag::err_omp_interop_var_multiple_actions) << VD;
17278+
if (DeclResult.first) {
17279+
if (!InteropVars.insert(DeclResult.first).second) {
17280+
Diag(ELoc, diag::err_omp_interop_var_multiple_actions)
17281+
<< DeclResult.first;
1727817282
return StmtError();
1727917283
}
1728017284
}
@@ -17286,16 +17290,20 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
1728617290
static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
1728717291
SourceLocation VarLoc,
1728817292
OpenMPClauseKind Kind) {
17289-
if (InteropVarExpr->isValueDependent() || InteropVarExpr->isTypeDependent() ||
17290-
InteropVarExpr->isInstantiationDependent() ||
17291-
InteropVarExpr->containsUnexpandedParameterPack())
17293+
SourceLocation ELoc;
17294+
SourceRange ERange;
17295+
Expr *RefExpr = InteropVarExpr;
17296+
auto Res =
17297+
getPrivateItem(SemaRef, RefExpr, ELoc, ERange,
17298+
/*AllowArraySection=*/false, /*DiagType=*/"omp_interop_t");
17299+
17300+
if (Res.second) {
17301+
// It will be analyzed later.
1729217302
return true;
17303+
}
1729317304

17294-
const auto *DRE = dyn_cast<DeclRefExpr>(InteropVarExpr);
17295-
if (!DRE || !isa<VarDecl>(DRE->getDecl())) {
17296-
SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_expected) << 0;
17305+
if (!Res.first)
1729717306
return false;
17298-
}
1729917307

1730017308
// Interop variable should be of type omp_interop_t.
1730117309
bool HasError = false;

clang/test/OpenMP/interop_ast_print.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,57 @@
2323

2424
typedef void *omp_interop_t;
2525

26+
struct S {
27+
omp_interop_t o1;
28+
omp_interop_t o2;
29+
omp_interop_t o3;
30+
static omp_interop_t so;
31+
void foo();
32+
S();
33+
~S();
34+
};
35+
omp_interop_t S::so;
36+
37+
struct T {
38+
static void static_member_func();
39+
static omp_interop_t to;
40+
};
41+
omp_interop_t T::to;
42+
43+
void T::static_member_func() {
44+
omp_interop_t o1;
45+
//PRINT: #pragma omp interop init(target : o1)
46+
#pragma omp interop init(target:o1)
47+
48+
//PRINT: #pragma omp interop init(target : to)
49+
#pragma omp interop init(target: to)
50+
51+
//PRINT: #pragma omp interop init(target : T::to)
52+
#pragma omp interop init(target: T::to)
53+
54+
//PRINT: #pragma omp interop init(target : S::so)
55+
#pragma omp interop init(target: S::so)
56+
}
57+
58+
59+
S::S() {
60+
//PRINT: #pragma omp interop init(target : this->o1)
61+
#pragma omp interop init(target:o1)
62+
//PRINT: #pragma omp interop use(this->o1) init(target : this->o2)
63+
#pragma omp interop use(o1) init(target:o2)
64+
//PRINT: #pragma omp interop use(this->o2) init(target : this->o3)
65+
#pragma omp interop use(o2) init(target:o3)
66+
}
67+
S::~S() {
68+
//PRINT: #pragma omp interop destroy(this->o1) destroy(this->o2) destroy(this->o3)
69+
#pragma omp interop destroy(o1) destroy(o2) destroy(o3)
70+
}
71+
72+
void S::foo() {
73+
//PRINT: #pragma omp interop init(target : so)
74+
#pragma omp interop init(target:so)
75+
}
76+
2677
//PRINT-LABEL: void foo1(
2778
//DUMP-LABEL: FunctionDecl {{.*}} foo1
2879
void foo1(int *ap, int dev) {
@@ -196,6 +247,9 @@ void foo1(int *ap, int dev) {
196247
//DUMP: OMPUseClause
197248
//DUMP: DeclRefExpr{{.*}}'omp_interop_t'{{.*}}Var{{.*}}'J'
198249
#pragma omp interop destroy(I) use(J)
250+
251+
//PRINT: #pragma omp interop init(target : S::so)
252+
#pragma omp interop init(target: S::so)
199253
}
200254

201255
//DUMP: FunctionTemplateDecl{{.*}}fooTemp
@@ -274,6 +328,7 @@ void bar()
274328
fooTemp<3>();
275329
omp_interop_t Ivar;
276330
barTemp(Ivar);
331+
S s;
277332
}
278333

279334
#endif // HEADER

clang/test/OpenMP/interop_irbuilder.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,34 @@ void test1() {
2929
: D0, D1)
3030
}
3131

32+
struct S {
33+
omp_interop_t interop;
34+
void member_test();
35+
};
36+
37+
void S::member_test() {
38+
39+
int device_id = 4;
40+
int D0, D1;
41+
42+
#pragma omp interop init(target \
43+
: interop)
44+
45+
#pragma omp interop init(targetsync \
46+
: interop)
47+
48+
#pragma omp interop init(target \
49+
: interop) device(device_id)
50+
51+
#pragma omp interop init(targetsync \
52+
: interop) device(device_id)
53+
54+
#pragma omp interop use(interop) depend(in \
55+
: D0, D1) nowait
56+
57+
#pragma omp interop destroy(interop) depend(in \
58+
: D0, D1)
59+
}
3260
// CHECK-LABEL: @_Z5test1v(
3361
// CHECK-NEXT: entry:
3462
// CHECK-NEXT: [[DEVICE_ID:%.*]] = alloca i32, align 4
@@ -94,3 +122,77 @@ void test1() {
94122
// CHECK-NEXT: call void @__tgt_interop_destroy(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP25]], i32 0)
95123
// CHECK-NEXT: ret void
96124
//
125+
//
126+
// CHECK-LABEL: @_ZN1S11member_testEv(
127+
// CHECK-NEXT: entry:
128+
// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca %struct.S*, align 8
129+
// CHECK-NEXT: [[DEVICE_ID:%.*]] = alloca i32, align 4
130+
// CHECK-NEXT: [[D0:%.*]] = alloca i32, align 4
131+
// CHECK-NEXT: [[D1:%.*]] = alloca i32, align 4
132+
// CHECK-NEXT: [[DOTDEP_ARR_ADDR:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8
133+
// CHECK-NEXT: [[DEP_COUNTER_ADDR:%.*]] = alloca i64, align 8
134+
// CHECK-NEXT: [[DOTDEP_ARR_ADDR10:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8
135+
// CHECK-NEXT: [[DEP_COUNTER_ADDR11:%.*]] = alloca i64, align 8
136+
// CHECK-NEXT: store %struct.S* [[THIS:%.*]], %struct.S** [[THIS_ADDR]], align 8
137+
// CHECK-NEXT: [[THIS1:%.*]] = load %struct.S*, %struct.S** [[THIS_ADDR]], align 8
138+
// CHECK-NEXT: store i32 4, i32* [[DEVICE_ID]], align 4
139+
// CHECK-NEXT: [[INTEROP:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], %struct.S* [[THIS1]], i32 0, i32 0
140+
// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
141+
// CHECK-NEXT: call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i8** [[INTEROP]], i64 1, i32 -1, i32 0, i8* null, i32 0)
142+
// CHECK-NEXT: [[INTEROP2:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
143+
// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
144+
// CHECK-NEXT: call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], i8** [[INTEROP2]], i64 2, i32 -1, i32 0, i8* null, i32 0)
145+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[DEVICE_ID]], align 4
146+
// CHECK-NEXT: [[INTEROP4:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
147+
// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM5:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
148+
// CHECK-NEXT: call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM5]], i8** [[INTEROP4]], i64 1, i32 [[TMP0]], i32 0, i8* null, i32 0)
149+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[DEVICE_ID]], align 4
150+
// CHECK-NEXT: [[INTEROP6:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
151+
// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
152+
// CHECK-NEXT: call void @__tgt_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], i8** [[INTEROP6]], i64 2, i32 [[TMP1]], i32 0, i8* null, i32 0)
153+
// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR]], i64 0, i64 0
154+
// CHECK-NEXT: [[TMP3:%.*]] = ptrtoint i32* [[D0]] to i64
155+
// CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO:%.*]], %struct.kmp_depend_info* [[TMP2]], i64 0
156+
// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP4]], i32 0, i32 0
157+
// CHECK-NEXT: store i64 [[TMP3]], i64* [[TMP5]], align 8
158+
// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP4]], i32 0, i32 1
159+
// CHECK-NEXT: store i64 4, i64* [[TMP6]], align 8
160+
// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP4]], i32 0, i32 2
161+
// CHECK-NEXT: store i8 1, i8* [[TMP7]], align 8
162+
// CHECK-NEXT: [[TMP8:%.*]] = ptrtoint i32* [[D1]] to i64
163+
// CHECK-NEXT: [[TMP9:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP2]], i64 1
164+
// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP9]], i32 0, i32 0
165+
// CHECK-NEXT: store i64 [[TMP8]], i64* [[TMP10]], align 8
166+
// CHECK-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP9]], i32 0, i32 1
167+
// CHECK-NEXT: store i64 4, i64* [[TMP11]], align 8
168+
// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP9]], i32 0, i32 2
169+
// CHECK-NEXT: store i8 1, i8* [[TMP12]], align 8
170+
// CHECK-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR]], align 8
171+
// CHECK-NEXT: [[TMP13:%.*]] = bitcast %struct.kmp_depend_info* [[TMP2]] to i8*
172+
// CHECK-NEXT: [[INTEROP8:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
173+
// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM9:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
174+
// CHECK-NEXT: call void @__tgt_interop_use(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM9]], i8** [[INTEROP8]], i32 -1, i32 2, i8* [[TMP13]], i32 1)
175+
// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR10]], i64 0, i64 0
176+
// CHECK-NEXT: [[TMP15:%.*]] = ptrtoint i32* [[D0]] to i64
177+
// CHECK-NEXT: [[TMP16:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 0
178+
// CHECK-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP16]], i32 0, i32 0
179+
// CHECK-NEXT: store i64 [[TMP15]], i64* [[TMP17]], align 8
180+
// CHECK-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP16]], i32 0, i32 1
181+
// CHECK-NEXT: store i64 4, i64* [[TMP18]], align 8
182+
// CHECK-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP16]], i32 0, i32 2
183+
// CHECK-NEXT: store i8 1, i8* [[TMP19]], align 8
184+
// CHECK-NEXT: [[TMP20:%.*]] = ptrtoint i32* [[D1]] to i64
185+
// CHECK-NEXT: [[TMP21:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 1
186+
// CHECK-NEXT: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP21]], i32 0, i32 0
187+
// CHECK-NEXT: store i64 [[TMP20]], i64* [[TMP22]], align 8
188+
// CHECK-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP21]], i32 0, i32 1
189+
// CHECK-NEXT: store i64 4, i64* [[TMP23]], align 8
190+
// CHECK-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP21]], i32 0, i32 2
191+
// CHECK-NEXT: store i8 1, i8* [[TMP24]], align 8
192+
// CHECK-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR11]], align 8
193+
// CHECK-NEXT: [[TMP25:%.*]] = bitcast %struct.kmp_depend_info* [[TMP14]] to i8*
194+
// CHECK-NEXT: [[INTEROP12:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[THIS1]], i32 0, i32 0
195+
// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM13:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]])
196+
// CHECK-NEXT: call void @__tgt_interop_destroy(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM13]], i8** [[INTEROP12]], i32 -1, i32 2, i8* [[TMP25]], i32 0)
197+
// CHECK-NEXT: ret void
198+
//

0 commit comments

Comments
 (0)