Skip to content

Commit 79079c9

Browse files
committed
[OpenACC] Finish implementing 'routine' AST/Sema.
This is the last item of the OpenACC 3.3 spec. It includes the implicit-name version of 'routine', plus significant refactorings to make the two work together. The implicit name version is represented as an attribute on the function call. This patch also implements the clauses for the implicit-name version, as well as the A.3.4 warning.
1 parent 6bbd45d commit 79079c9

34 files changed

+1355
-226
lines changed

clang/include/clang/AST/Attr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class ASTContext;
3838
class AttributeCommonInfo;
3939
class FunctionDecl;
4040
class OMPTraitInfo;
41+
class OpenACCClause;
4142

4243
/// Attr - This represents one attribute.
4344
class Attr : public AttributeCommonInfo {

clang/include/clang/AST/DeclOpenACC.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ class OpenACCDeclareDecl final
102102
static bool classofKind(Kind K) { return K == OpenACCDeclare; }
103103
};
104104

105+
// Reprents a 'routine' directive with a name. When this has no name, it is
106+
// represented as an attribute.
105107
class OpenACCRoutineDecl final
106108
: public OpenACCConstructDecl,
107109
private llvm::TrailingObjects<OpenACCRoutineDecl, const OpenACCClause *> {
@@ -129,6 +131,8 @@ class OpenACCRoutineDecl final
129131
: OpenACCConstructDecl(OpenACCRoutine, DC, OpenACCDirectiveKind::Routine,
130132
StartLoc, DirLoc, EndLoc),
131133
FuncRef(FuncRef), ParensLoc(LParenLoc, RParenLoc) {
134+
assert(LParenLoc.isValid() &&
135+
"Cannot represent implicit name with this declaration");
132136
// Initialize the trailing storage.
133137
std::uninitialized_copy(Clauses.begin(), Clauses.end(),
134138
getTrailingObjects<const OpenACCClause *>());
@@ -148,13 +152,10 @@ class OpenACCRoutineDecl final
148152
static bool classofKind(Kind K) { return K == OpenACCRoutine; }
149153

150154
const Expr *getFunctionReference() const { return FuncRef; }
151-
152155
Expr *getFunctionReference() { return FuncRef; }
153156

154157
SourceLocation getLParenLoc() const { return ParensLoc.getBegin(); }
155158
SourceLocation getRParenLoc() const { return ParensLoc.getEnd(); }
156-
157-
bool hasNameSpecified() const { return !ParensLoc.getBegin().isInvalid(); }
158159
};
159160
} // namespace clang
160161

clang/include/clang/AST/OpenACCClause.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ class OpenACCBindClause final : public OpenACCClauseWithParams {
251251
}
252252
};
253253

254+
bool operator==(const OpenACCBindClause &LHS, const OpenACCBindClause &RHS);
255+
inline bool operator!=(const OpenACCBindClause &LHS,
256+
const OpenACCBindClause &RHS) {
257+
return !(LHS == RHS);
258+
}
259+
254260
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
255261
/// A 'device_type' or 'dtype' clause, takes a list of either an 'asterisk' or
256262
/// an identifier. The 'asterisk' means 'the rest'.

clang/include/clang/AST/TextNodeDumper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ class TextNodeDumper
426426
void VisitOpenACCAsteriskSizeExpr(const OpenACCAsteriskSizeExpr *S);
427427
void VisitOpenACCDeclareDecl(const OpenACCDeclareDecl *D);
428428
void VisitOpenACCRoutineDecl(const OpenACCRoutineDecl *D);
429+
void VisitOpenACCRoutineDeclAttr(const OpenACCRoutineDeclAttr *A);
429430
void VisitEmbedExpr(const EmbedExpr *S);
430431
void VisitAtomicExpr(const AtomicExpr *AE);
431432
void VisitConvertVectorExpr(const ConvertVectorExpr *S);

clang/include/clang/Basic/Attr.td

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,10 @@ class Attr {
693693
// content. Eg) It parses 3 args, but semantically takes 4 args. Opts out of
694694
// common attribute error checking.
695695
bit HasCustomParsing = 0;
696+
// Set to true if this attribute requires custom serialization after the
697+
// typical attribute serialization. This will cause tablegen to emit a call to
698+
// ASTRecordWriter::Add<Name>Attr and ASTRecordReader::read<Name>Attr.
699+
bit HasCustomSerialization = 0;
696700
// Set to true if all of the attribute's arguments should be parsed in an
697701
// unevaluated context.
698702
bit ParseArgumentsAsUnevaluated = 0;
@@ -4991,12 +4995,30 @@ def Atomic : StmtAttr {
49914995
}
49924996

49934997
def OpenACCRoutineAnnot : InheritableAttr {
4994-
// This attribute is used to mark that a function is targetted by a `routine`
4995-
// directive, so it dones't have a spelling and is always implicit.
4998+
// This attribute is used to mark that a function is targeted by a `routine`
4999+
// directive with a name for the purposes of checking the declaration later.
5000+
// We don't really need a link back to the declaration, as location is
5001+
// sufficient.
5002+
// We abuse the source locations on this a little, since we need two locations
5003+
// for various diagnostic purposes. The 'begin' location is the location of
5004+
// the Routine directive. We are using the 'end' location for any 'bind'
5005+
// clauses, since this is needed for a diagnostic.
49965006
let Spellings = [];
49975007
let Subjects = SubjectList<[Function]>;
49985008
let Documentation = [InternalOnly];
5009+
}
5010+
5011+
def OpenACCRoutineDecl :InheritableAttr {
5012+
// This attribute represents the 'routine' directive when spelled without a
5013+
// 'name'.
5014+
let Spellings = [Pragma<"acc", "routine">];
5015+
let Subjects = SubjectList<[Function]>;
5016+
let SemaHandler = 0;
5017+
let HasCustomParsing = 1;
5018+
let HasCustomSerialization = 1;
5019+
let Documentation = [InternalOnly];
49995020
let AdditionalMembers = [{
5000-
SourceLocation BindClause;
5021+
llvm::SmallVector<const OpenACCClause *> Clauses;
5022+
void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const;
50015023
}];
50025024
}

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13040,6 +13040,16 @@ def err_acc_magic_static_in_routine
1304013040
def err_acc_duplicate_bind
1304113041
: Error<"multiple 'routine' directives with 'bind' clauses are not "
1304213042
"permitted to refer to the same function">;
13043+
def err_acc_duplicate_unnamed_bind
13044+
: Error<"OpenACC 'bind' clause on a declaration must bind to the same name "
13045+
"as previous bind clauses">;
13046+
def warn_acc_confusing_routine_name
13047+
: Warning<"OpenACC 'routine' directive with a name refers to a function "
13048+
"with the same name as the function on the following line; this "
13049+
"may be unintended">,
13050+
InGroup<DiagGroup<"openacc-confusing-routine-name">>;
13051+
def err_acc_decl_for_routine
13052+
: Error<"expected function or lambda declaration for 'routine' construct">;
1304313053

1304413054
// AMDGCN builtins diagnostics
1304513055
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;

clang/include/clang/Parse/Parser.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3697,7 +3697,10 @@ class Parser : public CodeCompletionHandler {
36973697
/// diagnostic. Eventually will be split into a few functions to parse
36983698
/// different situations.
36993699
public:
3700-
DeclGroupPtrTy ParseOpenACCDirectiveDecl();
3700+
DeclGroupPtrTy ParseOpenACCDirectiveDecl(AccessSpecifier &AS,
3701+
ParsedAttributes &Attrs,
3702+
DeclSpec::TST TagType,
3703+
Decl *TagDecl);
37013704
StmtResult ParseOpenACCDirectiveStmt();
37023705

37033706
private:
@@ -3831,6 +3834,11 @@ class Parser : public CodeCompletionHandler {
38313834
OpenACCGangArgRes ParseOpenACCGangArg(SourceLocation GangLoc);
38323835
/// Parses a 'condition' expr, ensuring it results in a
38333836
ExprResult ParseOpenACCConditionExpr();
3837+
DeclGroupPtrTy
3838+
ParseOpenACCAfterRoutineDecl(AccessSpecifier &AS, ParsedAttributes &Attrs,
3839+
DeclSpec::TST TagType, Decl *TagDecl,
3840+
OpenACCDirectiveParseInfo &DirInfo);
3841+
StmtResult ParseOpenACCAfterRoutineStmt(OpenACCDirectiveParseInfo &DirInfo);
38343842

38353843
private:
38363844
//===--------------------------------------------------------------------===//

clang/include/clang/Sema/SemaOpenACC.h

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
namespace clang {
3232
class IdentifierInfo;
3333
class OpenACCClause;
34+
class Scope;
3435

3536
class SemaOpenACC : public SemaBase {
3637
public:
@@ -172,6 +173,9 @@ class SemaOpenACC : public SemaBase {
172173
// check them later.
173174
llvm::SmallDenseMap<const clang::FunctionDecl *, SourceLocation>
174175
MagicStaticLocs;
176+
OpenACCRoutineDecl *LastRoutineDecl = nullptr;
177+
178+
void CheckLastRoutineDeclNameConflict(const NamedDecl *ND);
175179

176180
public:
177181
ComputeConstructInfo &getActiveComputeConstructInfo() {
@@ -763,10 +767,37 @@ class SemaOpenACC : public SemaBase {
763767

764768
/// Called after the directive has been completely parsed, including the
765769
/// declaration group or associated statement.
766-
DeclGroupRef ActOnEndDeclDirective(
767-
OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc,
768-
SourceLocation LParenLoc, Expr *FuncRef, SourceLocation RParenLoc,
769-
SourceLocation EndLoc, ArrayRef<OpenACCClause *> Clauses);
770+
DeclGroupRef
771+
ActOnEndDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc,
772+
SourceLocation DirLoc, SourceLocation LParenLoc,
773+
SourceLocation RParenLoc, SourceLocation EndLoc,
774+
ArrayRef<OpenACCClause *> Clauses);
775+
776+
// Helper functions for ActOnEndRoutine*Directive, which does all the checking
777+
// given the proper list of declarations.
778+
void CheckRoutineDecl(SourceLocation DirLoc,
779+
ArrayRef<const OpenACCClause *> Clauses,
780+
Decl *NextParsedDecl);
781+
OpenACCRoutineDecl *CheckRoutineDecl(SourceLocation StartLoc,
782+
SourceLocation DirLoc,
783+
SourceLocation LParenLoc, Expr *FuncRef,
784+
SourceLocation RParenLoc,
785+
ArrayRef<const OpenACCClause *> Clauses,
786+
SourceLocation EndLoc);
787+
OpenACCRoutineDeclAttr *
788+
mergeRoutineDeclAttr(const OpenACCRoutineDeclAttr &Old);
789+
DeclGroupRef
790+
ActOnEndRoutineDeclDirective(SourceLocation StartLoc, SourceLocation DirLoc,
791+
SourceLocation LParenLoc, Expr *ReferencedFunc,
792+
SourceLocation RParenLoc,
793+
ArrayRef<const OpenACCClause *> Clauses,
794+
SourceLocation EndLoc, DeclGroupPtrTy NextDecl);
795+
StmtResult
796+
ActOnEndRoutineStmtDirective(SourceLocation StartLoc, SourceLocation DirLoc,
797+
SourceLocation LParenLoc, Expr *ReferencedFunc,
798+
SourceLocation RParenLoc,
799+
ArrayRef<const OpenACCClause *> Clauses,
800+
SourceLocation EndLoc, Stmt *NextStmt);
770801

771802
/// Called when encountering an 'int-expr' for OpenACC, and manages
772803
/// conversions and diagnostics to 'int'.
@@ -780,8 +811,14 @@ class SemaOpenACC : public SemaBase {
780811
/// Helper function called by ActonVar that is used to check a 'cache' var.
781812
ExprResult ActOnCacheVar(Expr *VarExpr);
782813
/// Function called when a variable declarator is created, which lets us
783-
/// impelment the 'routine' 'function static variables' restriction.
814+
/// implement the 'routine' 'function static variables' restriction.
784815
void ActOnVariableDeclarator(VarDecl *VD);
816+
/// Called when a function decl is created, which lets us implement the
817+
/// 'routine' 'doesn't match next thing' warning.
818+
void ActOnFunctionDeclarator(FunctionDecl *FD);
819+
/// Called when a variable is initialized, so we can implement the 'routine
820+
/// 'doesn't match the next thing' warning for lambda init.
821+
void ActOnVariableInit(VarDecl *VD, QualType InitType);
785822

786823
// Called after 'ActOnVar' specifically for a 'link' clause, which has to do
787824
// some minor additional checks.

clang/include/clang/Serialization/ASTRecordReader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ class ASTRecordReader
282282
/// statement reading.
283283
void readOpenACCClauseList(MutableArrayRef<const OpenACCClause *> Clauses);
284284

285+
void readOpenACCRoutineDeclAttr(OpenACCRoutineDeclAttr *A);
286+
285287
/// Read a source location, advancing Idx.
286288
SourceLocation readSourceLocation(LocSeq *Seq = nullptr) {
287289
return Reader->ReadSourceLocation(*F, Record, Idx, Seq);

clang/include/clang/Serialization/ASTRecordWriter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,8 @@ class ASTRecordWriter
307307
/// Writes out a list of OpenACC clauses.
308308
void writeOpenACCClauseList(ArrayRef<const OpenACCClause *> Clauses);
309309

310+
void AddOpenACCRoutineDeclAttr(const OpenACCRoutineDeclAttr *A);
311+
310312
/// Emit a string.
311313
void AddString(StringRef Str) {
312314
return Writer->AddString(Str, *Record);

clang/lib/AST/DeclOpenACC.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "clang/AST/DeclOpenACC.h"
1414
#include "clang/AST/ASTContext.h"
15+
#include "clang/AST/Attr.h"
16+
#include "clang/AST/OpenACCClause.h"
1517

1618
using namespace clang;
1719

@@ -50,3 +52,12 @@ OpenACCRoutineDecl::CreateDeserialized(ASTContext &Ctx, GlobalDeclID ID,
5052
return new (Ctx, ID, additionalSizeToAlloc<const OpenACCClause *>(NumClauses))
5153
OpenACCRoutineDecl(NumClauses);
5254
}
55+
56+
void OpenACCRoutineDeclAttr::printPrettyPragma(
57+
llvm::raw_ostream &OS, const clang::PrintingPolicy &P) const {
58+
if (Clauses.size() > 0) {
59+
OS << ' ';
60+
OpenACCClausePrinter Printer{OS, P};
61+
Printer.VisitClauseList(Clauses);
62+
}
63+
}

clang/lib/AST/DeclPrinter.cpp

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ namespace {
4949
QualType T);
5050

5151
void PrintObjCTypeParams(ObjCTypeParamList *Params);
52+
void PrintOpenACCRoutineOnLambda(Decl *D);
5253

5354
public:
5455
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
@@ -292,10 +293,34 @@ bool DeclPrinter::prettyPrintAttributes(const Decl *D,
292293
return hasPrinted;
293294
}
294295

296+
void DeclPrinter::PrintOpenACCRoutineOnLambda(Decl *D) {
297+
CXXRecordDecl *CXXRD = nullptr;
298+
if (const auto *VD = dyn_cast<VarDecl>(D)) {
299+
if (const auto *Init = VD->getInit())
300+
CXXRD = Init->getType().isNull() ? nullptr
301+
: Init->getType()->getAsCXXRecordDecl();
302+
} else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
303+
CXXRD =
304+
FD->getType().isNull() ? nullptr : FD->getType()->getAsCXXRecordDecl();
305+
}
306+
307+
if (!CXXRD || !CXXRD->isLambda())
308+
return;
309+
310+
if (const auto *Call = CXXRD->getLambdaCallOperator()) {
311+
for (auto *A : Call->specific_attrs<OpenACCRoutineDeclAttr>()) {
312+
A->printPretty(Out, Policy);
313+
Indent();
314+
}
315+
}
316+
}
317+
295318
void DeclPrinter::prettyPrintPragmas(Decl *D) {
296319
if (Policy.PolishForDeclaration)
297320
return;
298321

322+
PrintOpenACCRoutineOnLambda(D);
323+
299324
if (D->hasAttrs()) {
300325
AttrVec &Attrs = D->getAttrs();
301326
for (auto *A : Attrs) {
@@ -894,6 +919,7 @@ void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
894919
}
895920

896921
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
922+
prettyPrintPragmas(D);
897923
// FIXME: add printing of pragma attributes if required.
898924
if (!Policy.SuppressSpecifiers && D->isMutable())
899925
Out << "mutable ";
@@ -1930,19 +1956,17 @@ void DeclPrinter::VisitOpenACCRoutineDecl(OpenACCRoutineDecl *D) {
19301956
if (!D->isInvalidDecl()) {
19311957
Out << "#pragma acc routine";
19321958

1933-
if (D->hasNameSpecified()) {
1934-
Out << "(";
1959+
Out << "(";
19351960

1936-
// The referenced function was named here, but this makes us tolerant of
1937-
// errors.
1938-
if (D->getFunctionReference())
1939-
D->getFunctionReference()->printPretty(Out, nullptr, Policy,
1940-
Indentation, "\n", &Context);
1941-
else
1942-
Out << "<error>";
1961+
// The referenced function was named here, but this makes us tolerant of
1962+
// errors.
1963+
if (D->getFunctionReference())
1964+
D->getFunctionReference()->printPretty(Out, nullptr, Policy, Indentation,
1965+
"\n", &Context);
1966+
else
1967+
Out << "<error>";
19431968

1944-
Out << ")";
1945-
}
1969+
Out << ")";
19461970

19471971
if (!D->clauses().empty()) {
19481972
Out << ' ';

clang/lib/AST/OpenACCClause.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,18 @@ OpenACCBindClause *OpenACCBindClause::Create(const ASTContext &C,
628628
return new (Mem) OpenACCBindClause(BeginLoc, LParenLoc, ID, EndLoc);
629629
}
630630

631+
bool clang::operator==(const OpenACCBindClause &LHS,
632+
const OpenACCBindClause &RHS) {
633+
if (LHS.isStringArgument() != RHS.isStringArgument())
634+
return false;
635+
636+
if (LHS.isStringArgument())
637+
return LHS.getStringArgument()->getString() ==
638+
RHS.getStringArgument()->getString();
639+
return LHS.getIdentifierArgument()->getName() ==
640+
RHS.getIdentifierArgument()->getName();
641+
}
642+
631643
//===----------------------------------------------------------------------===//
632644
// OpenACC clauses printing methods
633645
//===----------------------------------------------------------------------===//

clang/lib/AST/TextNodeDumper.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3090,10 +3090,7 @@ void TextNodeDumper::VisitOpenACCDeclareDecl(const OpenACCDeclareDecl *D) {
30903090
void TextNodeDumper::VisitOpenACCRoutineDecl(const OpenACCRoutineDecl *D) {
30913091
OS << " " << D->getDirectiveKind();
30923092

3093-
if (D->hasNameSpecified()) {
3094-
OS << " name_specified";
3095-
dumpSourceRange(SourceRange{D->getLParenLoc(), D->getRParenLoc()});
3096-
}
3093+
dumpSourceRange(SourceRange{D->getLParenLoc(), D->getRParenLoc()});
30973094

30983095
AddChild([=] { Visit(D->getFunctionReference()); });
30993096

@@ -3105,6 +3102,16 @@ void TextNodeDumper::VisitOpenACCRoutineDecl(const OpenACCRoutineDecl *D) {
31053102
});
31063103
}
31073104

3105+
void TextNodeDumper::VisitOpenACCRoutineDeclAttr(
3106+
const OpenACCRoutineDeclAttr *A) {
3107+
for (const OpenACCClause *C : A->Clauses)
3108+
AddChild([=] {
3109+
Visit(C);
3110+
for (const Stmt *S : C->children())
3111+
AddChild([=] { Visit(S); });
3112+
});
3113+
}
3114+
31083115
void TextNodeDumper::VisitEmbedExpr(const EmbedExpr *S) {
31093116
AddChild("begin", [=] { OS << S->getStartingElementPos(); });
31103117
AddChild("number of elements", [=] { OS << S->getDataElementCount(); });

0 commit comments

Comments
 (0)