Skip to content

Commit 5b50f08

Browse files
committed
Correct implementation of 'device_type' on routine
After looking into it further, the rule for the 'worker', 'gang', 'vector', and 'seq' on a 'routine' construct are suppsoed to be more complicated. The area BEFORE the first device_type are 'global' and apply to all following device_types. Then, each device_type region can name their own. The rule is it is exclusive on a per-device_type basis for these.
1 parent 3a8a5bb commit 5b50f08

File tree

5 files changed

+671
-6
lines changed

5 files changed

+671
-6
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12912,6 +12912,16 @@ def err_acc_clause_after_device_type
1291212912
def err_acc_clause_cannot_combine
1291312913
: Error<"OpenACC clause '%0' may not appear on the same construct as a "
1291412914
"'%1' clause on a '%2' construct">;
12915+
def err_acc_clause_routine_cannot_combine_before_device_type
12916+
: Error<"OpenACC clause '%0' after 'device_type' clause on a 'routine' "
12917+
"conflicts with the '%1' clause before the first 'device_type'">;
12918+
def err_acc_clause_routine_cannot_combine_same_device_type
12919+
: Error<"OpenACC clause '%0' on a 'routine' directive conflicts with the "
12920+
"'%1' clause applying to the same 'device_type'">;
12921+
def err_acc_clause_routine_one_of_in_region
12922+
: Error<"OpenACC 'routine' construct must have at least one 'gang', 'seq', "
12923+
"'vector', or 'worker' clause that applies to each 'device_type'">;
12924+
1291512925
def err_acc_reduction_num_gangs_conflict
1291612926
: Error<"OpenACC '%1' clause %select{|with more than 1 argument }0may not "
1291712927
"appear on a '%2' construct "
@@ -12980,9 +12990,10 @@ def err_acc_gang_reduction_numgangs_conflict
1298012990
"'%1' clause %select{inside a compute construct with a|and a}3 "
1298112991
"'num_gangs' clause with more than one argument">;
1298212992

12983-
def err_reduction_op_mismatch
12993+
def err_reduction_op_mismatch
1298412994
: Error<"OpenACC 'reduction' variable must have the same operator in all "
1298512995
"nested constructs (%0 vs %1)">;
12996+
1298612997
def err_acc_loop_variable_type
1298712998
: Error<"loop variable of loop associated with an OpenACC '%0' construct "
1298812999
"must be of integer, pointer, or random-access-iterator type (is "

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,6 +1828,62 @@ StmtResult SemaOpenACC::ActOnAssociatedStmt(
18281828
llvm_unreachable("Invalid associated statement application");
18291829
}
18301830

1831+
namespace {
1832+
1833+
// Routine has some pretty complicated set of rules for how device_type
1834+
// interacts with 'gang', 'worker', 'vector', and 'seq'. Enforce part of it
1835+
// here.
1836+
bool CheckValidRoutineGangWorkerVectorSeqClauses(
1837+
SemaOpenACC &SemaRef, SourceLocation DirectiveLoc,
1838+
ArrayRef<const OpenACCClause *> Clauses) {
1839+
auto RequiredPred = llvm::IsaPred<OpenACCGangClause, OpenACCWorkerClause,
1840+
OpenACCVectorClause, OpenACCSeqClause>;
1841+
// The clause handling has assured us that there is no duplicates. That is,
1842+
// if there is 1 before a device_type, there are none after a device_type.
1843+
// If not, there is at most 1 applying to each device_type.
1844+
1845+
// What is left to legalize is that either:
1846+
// 1- there is 1 before the first device_type.
1847+
// 2- there is 1 AFTER each device_type.
1848+
auto *FirstDeviceType =
1849+
llvm::find_if(Clauses, llvm::IsaPred<OpenACCDeviceTypeClause>);
1850+
1851+
// If there is 1 before the first device_type (or at all if no device_type),
1852+
// we are legal.
1853+
auto *ClauseItr =
1854+
std::find_if(Clauses.begin(), FirstDeviceType, RequiredPred);
1855+
1856+
if (ClauseItr != FirstDeviceType)
1857+
return false;
1858+
1859+
// If there IS no device_type, and no clause, diagnose.
1860+
if (FirstDeviceType == Clauses.end())
1861+
return SemaRef.Diag(DirectiveLoc, diag::err_acc_construct_one_clause_of)
1862+
<< OpenACCDirectiveKind::Routine
1863+
<< "'gang', 'seq', 'vector', or 'worker'";
1864+
1865+
// Else, we have to check EACH device_type group. PrevDeviceType is the
1866+
// device-type before the current group.
1867+
auto *PrevDeviceType = FirstDeviceType;
1868+
1869+
while (PrevDeviceType != Clauses.end()) {
1870+
auto *NextDeviceType =
1871+
std::find_if(std::next(PrevDeviceType), Clauses.end(),
1872+
llvm::IsaPred<OpenACCDeviceTypeClause>);
1873+
1874+
ClauseItr = std::find_if(PrevDeviceType, NextDeviceType, RequiredPred);
1875+
1876+
if (ClauseItr == NextDeviceType)
1877+
return SemaRef.Diag((*PrevDeviceType)->getBeginLoc(),
1878+
diag::err_acc_clause_routine_one_of_in_region);
1879+
1880+
PrevDeviceType = NextDeviceType;
1881+
}
1882+
1883+
return false;
1884+
}
1885+
} // namespace
1886+
18311887
bool SemaOpenACC::ActOnStartDeclDirective(
18321888
OpenACCDirectiveKind K, SourceLocation StartLoc,
18331889
ArrayRef<const OpenACCClause *> Clauses) {
@@ -1839,6 +1895,9 @@ bool SemaOpenACC::ActOnStartDeclDirective(
18391895

18401896
if (DiagnoseRequiredClauses(K, StartLoc, Clauses))
18411897
return true;
1898+
if (K == OpenACCDirectiveKind::Routine &&
1899+
CheckValidRoutineGangWorkerVectorSeqClauses(*this, StartLoc, Clauses))
1900+
return true;
18421901

18431902
return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/false);
18441903
}

clang/lib/Sema/SemaOpenACCClause.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,93 @@ class SemaOpenACCClauseVisitor {
199199
llvm_unreachable("didn't return from switch above?");
200200
}
201201

202+
// Routine has a pretty complicated set of rules for how device_type and the
203+
// gang, worker, vector, and seq clauses work. So diagnose some of it here.
204+
bool CheckValidRoutineGangWorkerVectorSeqNewClause(
205+
SemaOpenACC::OpenACCParsedClause &Clause) {
206+
if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Routine)
207+
return false;
208+
209+
if (Clause.getClauseKind() != OpenACCClauseKind::Gang &&
210+
Clause.getClauseKind() != OpenACCClauseKind::Vector &&
211+
Clause.getClauseKind() != OpenACCClauseKind::Worker &&
212+
Clause.getClauseKind() != OpenACCClauseKind::Seq)
213+
return false;
214+
auto ProhibitedPred = llvm::IsaPred<OpenACCGangClause, OpenACCWorkerClause,
215+
OpenACCVectorClause, OpenACCSeqClause>;
216+
217+
auto *FirstDeviceType =
218+
llvm::find_if(ExistingClauses, llvm::IsaPred<OpenACCDeviceTypeClause>);
219+
220+
if (FirstDeviceType == ExistingClauses.end()) {
221+
// If there isn't a device type yet, ANY duplicate is wrong.
222+
223+
auto *ExistingProhibitedClause =
224+
llvm::find_if(ExistingClauses, ProhibitedPred);
225+
226+
if (ExistingProhibitedClause == ExistingClauses.end())
227+
return false;
228+
229+
SemaRef.Diag(Clause.getBeginLoc(), diag::err_acc_clause_cannot_combine)
230+
<< Clause.getClauseKind()
231+
<< (*ExistingProhibitedClause)->getClauseKind()
232+
<< Clause.getDirectiveKind();
233+
SemaRef.Diag((*ExistingProhibitedClause)->getBeginLoc(),
234+
diag::note_acc_previous_clause_here);
235+
return true;
236+
}
237+
238+
// At this point we know that this is 'after' a device type. So this is an
239+
// error if: 1- there is one BEFORE the 'device_type' 2- there is one
240+
// between this and the previous 'device_type'.
241+
242+
auto *BeforeDeviceType =
243+
std::find_if(ExistingClauses.begin(), FirstDeviceType, ProhibitedPred);
244+
245+
// If there is one before the device_type (and we know we are after a
246+
// device_type), than this is ill-formed.
247+
if (BeforeDeviceType != FirstDeviceType) {
248+
SemaRef.Diag(
249+
Clause.getBeginLoc(),
250+
diag::err_acc_clause_routine_cannot_combine_before_device_type)
251+
<< Clause.getClauseKind() << (*BeforeDeviceType)->getClauseKind();
252+
SemaRef.Diag((*BeforeDeviceType)->getBeginLoc(),
253+
diag::note_acc_previous_clause_here);
254+
SemaRef.Diag((*FirstDeviceType)->getBeginLoc(),
255+
diag::note_acc_previous_clause_here);
256+
return true;
257+
}
258+
259+
auto LastDeviceTypeItr =
260+
std::find_if(ExistingClauses.rbegin(), ExistingClauses.rend(),
261+
llvm::IsaPred<OpenACCDeviceTypeClause>);
262+
263+
// We already know there is one in the list, so it is nonsensical to not
264+
// have one.
265+
assert(LastDeviceTypeItr != ExistingClauses.rend());
266+
267+
// Get the device-type from-the-front (not reverse) iterator from the
268+
// reverse iterator.
269+
auto *LastDeviceType = LastDeviceTypeItr.base() - 1;
270+
271+
auto *ExistingProhibitedSinceLastDevice =
272+
std::find_if(LastDeviceType, ExistingClauses.end(), ProhibitedPred);
273+
274+
// No prohibited ones since the last device-type.
275+
if (ExistingProhibitedSinceLastDevice == ExistingClauses.end())
276+
return false;
277+
278+
SemaRef.Diag(Clause.getBeginLoc(),
279+
diag::err_acc_clause_routine_cannot_combine_same_device_type)
280+
<< Clause.getClauseKind()
281+
<< (*ExistingProhibitedSinceLastDevice)->getClauseKind();
282+
SemaRef.Diag((*ExistingProhibitedSinceLastDevice)->getBeginLoc(),
283+
diag::note_acc_previous_clause_here);
284+
SemaRef.Diag((*LastDeviceType)->getBeginLoc(),
285+
diag::note_acc_previous_clause_here);
286+
return true;
287+
}
288+
202289
public:
203290
SemaOpenACCClauseVisitor(SemaOpenACC &S,
204291
ArrayRef<const OpenACCClause *> ExistingClauses)
@@ -213,6 +300,8 @@ class SemaOpenACCClauseVisitor {
213300
Clause.getClauseKind(),
214301
Clause.getBeginLoc(), ExistingClauses))
215302
return nullptr;
303+
if (CheckValidRoutineGangWorkerVectorSeqNewClause(Clause))
304+
return nullptr;
216305

217306
switch (Clause.getClauseKind()) {
218307
case OpenACCClauseKind::Shortloop:

clang/test/ParserOpenACC/parse-constructs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,20 +153,20 @@ void func() {
153153
#pragma acc routine seq
154154
void routine_func();
155155
// expected-error@+2{{invalid OpenACC clause 'clause'}}
156-
// expected-error@+1{{OpenACC 'routine' construct must have at least one 'gang', 'worker', 'vector' or 'seq' clause}}
156+
// expected-error@+1{{OpenACC 'routine' construct must have at least one 'gang', 'seq', 'vector', or 'worker' clause}}
157157
#pragma acc routine clause list
158158
void routine_func();
159159

160160
// expected-error@+1{{use of undeclared identifier 'func_name'}}
161161
#pragma acc routine (func_name) seq
162162
// expected-error@+3{{use of undeclared identifier 'func_name'}}
163163
// expected-error@+2{{invalid OpenACC clause 'clause'}}
164-
// expected-error@+1{{OpenACC 'routine' construct must have at least one 'gang', 'worker', 'vector' or 'seq' clause}}
164+
// expected-error@+1{{OpenACC 'routine' construct must have at least one 'gang', 'seq', 'vector', or 'worker' clause}}
165165
#pragma acc routine (func_name) clause list
166166

167167
#pragma acc routine (routine_func) seq
168168
// expected-error@+2{{invalid OpenACC clause 'clause'}}
169-
// expected-error@+1{{OpenACC 'routine' construct must have at least one 'gang', 'worker', 'vector' or 'seq' clause}}
169+
// expected-error@+1{{OpenACC 'routine' construct must have at least one 'gang', 'seq', 'vector', or 'worker' clause}}
170170
#pragma acc routine (routine_func) clause list
171171

172172
// expected-error@+2{{expected ')'}}

0 commit comments

Comments
 (0)