forked from OSchip/llvm-project
[OPENMP 4.5] Ccapture/codegen of private non-static data members.
OpenMP 4.5 introduces privatization of non-static data members of current class in non-static member functions. To correctly handle such kind of privatization a new (pseudo)declaration VarDecl-based node is added. It allows to reuse an existing code for capturing variables in Lambdas/Block/Captured blocks of code for correct privatization and codegen. llvm-svn: 260077
This commit is contained in:
parent
9ab99ab985
commit
90c228f0ba
|
@ -87,6 +87,35 @@ public:
|
|||
static bool classofKind(Kind K) { return K == OMPThreadPrivate; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
/// Pseudo declaration for capturing of non-static data members in non-static
|
||||
/// member functions.
|
||||
///
|
||||
/// Clang supports capturing of variables only, but OpenMP 4.5 allows to
|
||||
/// privatize non-static members of current class in non-static member
|
||||
/// functions. This pseudo-declaration allows properly handle this kind of
|
||||
/// capture by wrapping captured expression into a variable-like declaration.
|
||||
class OMPCapturedFieldDecl final : public VarDecl {
|
||||
friend class ASTDeclReader;
|
||||
void anchor() override;
|
||||
|
||||
OMPCapturedFieldDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id,
|
||||
QualType Type)
|
||||
: VarDecl(OMPCapturedField, C, DC, SourceLocation(), SourceLocation(), Id,
|
||||
Type, nullptr, SC_None) {
|
||||
setImplicit();
|
||||
}
|
||||
|
||||
public:
|
||||
static OMPCapturedFieldDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
IdentifierInfo *Id, QualType T);
|
||||
|
||||
static OMPCapturedFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == OMPCapturedField; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1434,6 +1434,8 @@ DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
|
|||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(OMPCapturedFieldDecl, { TRY_TO(TraverseVarHelper(D)); })
|
||||
|
||||
// A helper method for TemplateDecl's children.
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
|
||||
|
|
|
@ -51,6 +51,7 @@ def Named : Decl<1>;
|
|||
: DDecl<VarTemplateSpecialization>;
|
||||
def ImplicitParam : DDecl<Var>;
|
||||
def ParmVar : DDecl<Var>;
|
||||
def OMPCapturedField : DDecl<Var>;
|
||||
def NonTypeTemplateParm : DDecl<Declarator>;
|
||||
def Template : DDecl<Named, 1>;
|
||||
def RedeclarableTemplate : DDecl<Template, 1>;
|
||||
|
|
|
@ -7789,7 +7789,9 @@ public:
|
|||
/// \brief Check if the specified variable is used in one of the private
|
||||
/// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP
|
||||
/// constructs.
|
||||
bool IsOpenMPCapturedDecl(ValueDecl *D);
|
||||
VarDecl *IsOpenMPCapturedDecl(ValueDecl *D);
|
||||
ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK,
|
||||
ExprObjectKind OK);
|
||||
|
||||
/// \brief Check if the specified variable is used in 'private' clause.
|
||||
/// \param Level Relative level of nested OpenMP construct for that the check
|
||||
|
|
|
@ -1163,6 +1163,8 @@ namespace clang {
|
|||
DECL_EMPTY,
|
||||
/// \brief An ObjCTypeParamDecl record.
|
||||
DECL_OBJC_TYPE_PARAM,
|
||||
/// \brief An OMPCapturedFieldDecl record.
|
||||
DECL_OMP_CAPTUREDFIELD,
|
||||
};
|
||||
|
||||
/// \brief Record codes for each kind of statement or expression.
|
||||
|
|
|
@ -655,6 +655,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|||
case ObjCCategoryImpl:
|
||||
case Import:
|
||||
case OMPThreadPrivate:
|
||||
case OMPCapturedField:
|
||||
case Empty:
|
||||
// Never looked up by name.
|
||||
return 0;
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// \brief This file implements OMPThreadPrivateDecl class.
|
||||
/// \brief This file implements OMPThreadPrivateDecl, OMPCapturedFieldDecl
|
||||
/// classes.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
@ -52,3 +53,21 @@ void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
|
|||
std::uninitialized_copy(VL.begin(), VL.end(), getTrailingObjects<Expr *>());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OMPCapturedFieldDecl Implementation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void OMPCapturedFieldDecl::anchor() {}
|
||||
|
||||
OMPCapturedFieldDecl *OMPCapturedFieldDecl::Create(ASTContext &C,
|
||||
DeclContext *DC,
|
||||
IdentifierInfo *Id,
|
||||
QualType T) {
|
||||
return new (C, DC) OMPCapturedFieldDecl(C, DC, Id, T);
|
||||
}
|
||||
|
||||
OMPCapturedFieldDecl *OMPCapturedFieldDecl::CreateDeserialized(ASTContext &C,
|
||||
unsigned ID) {
|
||||
return new (C, ID) OMPCapturedFieldDecl(C, nullptr, nullptr, QualType());
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ namespace {
|
|||
void VisitUsingDecl(UsingDecl *D);
|
||||
void VisitUsingShadowDecl(UsingShadowDecl *D);
|
||||
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
|
||||
void VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D);
|
||||
|
||||
void PrintTemplateParameters(const TemplateParameterList *Params,
|
||||
const TemplateArgumentList *Args = nullptr);
|
||||
|
@ -1366,3 +1367,7 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D) {
|
||||
D->getInit()->printPretty(Out, nullptr, Policy, Indentation);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclOpenMP.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
@ -763,15 +764,16 @@ template<typename T>
|
|||
void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
|
||||
for (typename T::varlist_iterator I = Node->varlist_begin(),
|
||||
E = Node->varlist_end();
|
||||
I != E; ++I) {
|
||||
I != E; ++I) {
|
||||
assert(*I && "Expected non-null Stmt");
|
||||
OS << (I == Node->varlist_begin() ? StartSym : ',');
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(*I)) {
|
||||
OS << (I == Node->varlist_begin() ? StartSym : ',');
|
||||
cast<NamedDecl>(DRE->getDecl())->printQualifiedName(OS);
|
||||
} else {
|
||||
OS << (I == Node->varlist_begin() ? StartSym : ',');
|
||||
if (auto *CFD = dyn_cast<OMPCapturedFieldDecl>(DRE->getDecl()))
|
||||
CFD->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy, 0);
|
||||
else
|
||||
DRE->getDecl()->printQualifiedName(OS);
|
||||
} else
|
||||
(*I)->printPretty(OS, nullptr, Policy, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
|||
case Decl::Label: // __label__ x;
|
||||
case Decl::Import:
|
||||
case Decl::OMPThreadPrivate:
|
||||
case Decl::OMPCapturedField:
|
||||
case Decl::Empty:
|
||||
// None of these decls require codegen support.
|
||||
return;
|
||||
|
|
|
@ -2874,6 +2874,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
|
|||
case Decl::Var:
|
||||
case Decl::VarTemplateSpecialization:
|
||||
case Decl::VarTemplatePartialSpecialization:
|
||||
case Decl::OMPCapturedField:
|
||||
// In C, "extern void blah;" is valid and is an r-value.
|
||||
if (!getLangOpts().CPlusPlus &&
|
||||
!type.hasQualifiers() &&
|
||||
|
|
|
@ -1735,9 +1735,19 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
|
|||
FoundDecl, Field);
|
||||
if (Base.isInvalid())
|
||||
return ExprError();
|
||||
return BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,
|
||||
/*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
|
||||
MemberNameInfo, MemberType, VK, OK);
|
||||
MemberExpr *ME =
|
||||
BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,
|
||||
/*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
|
||||
MemberNameInfo, MemberType, VK, OK);
|
||||
|
||||
// Build a reference to a private copy for non-static data members in
|
||||
// non-static member functions, privatized by OpenMP constructs.
|
||||
if (S.getLangOpts().OpenMP && IsArrow &&
|
||||
isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
|
||||
if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field))
|
||||
return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK);
|
||||
}
|
||||
return ME;
|
||||
}
|
||||
|
||||
/// Builds an implicit member access expression. The current context
|
||||
|
|
|
@ -71,10 +71,11 @@ public:
|
|||
OpenMPDirectiveKind DKind;
|
||||
OpenMPClauseKind CKind;
|
||||
Expr *RefExpr;
|
||||
DeclRefExpr *PrivateCopy;
|
||||
SourceLocation ImplicitDSALoc;
|
||||
DSAVarData()
|
||||
: DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr),
|
||||
ImplicitDSALoc() {}
|
||||
PrivateCopy(nullptr), ImplicitDSALoc() {}
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -83,11 +84,12 @@ private:
|
|||
struct DSAInfo {
|
||||
OpenMPClauseKind Attributes;
|
||||
Expr *RefExpr;
|
||||
DeclRefExpr *PrivateCopy;
|
||||
};
|
||||
typedef llvm::SmallDenseMap<ValueDecl *, DSAInfo, 64> DeclSAMapTy;
|
||||
typedef llvm::SmallDenseMap<ValueDecl *, Expr *, 64> AlignedMapTy;
|
||||
typedef llvm::DenseMap<ValueDecl *, DSAInfo> DeclSAMapTy;
|
||||
typedef llvm::DenseMap<ValueDecl *, Expr *> AlignedMapTy;
|
||||
typedef llvm::DenseMap<ValueDecl *, unsigned> LoopControlVariablesMapTy;
|
||||
typedef llvm::SmallDenseMap<ValueDecl *, MapInfo, 64> MappedDeclsTy;
|
||||
typedef llvm::DenseMap<ValueDecl *, MapInfo> MappedDeclsTy;
|
||||
typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>>
|
||||
CriticalsWithHintsTy;
|
||||
|
||||
|
@ -195,7 +197,8 @@ public:
|
|||
ValueDecl *getParentLoopControlVariable(unsigned I);
|
||||
|
||||
/// \brief Adds explicit data sharing attribute to the specified declaration.
|
||||
void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A);
|
||||
void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
|
||||
DeclRefExpr *PrivateCopy = nullptr);
|
||||
|
||||
/// \brief Returns data sharing attributes from top of the stack for the
|
||||
/// specified declaration.
|
||||
|
@ -434,6 +437,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
|
|||
// attributes.
|
||||
if (Iter->SharingMap.count(D)) {
|
||||
DVar.RefExpr = Iter->SharingMap[D].RefExpr;
|
||||
DVar.PrivateCopy = Iter->SharingMap[D].PrivateCopy;
|
||||
DVar.CKind = Iter->SharingMap[D].Attributes;
|
||||
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
|
||||
return DVar;
|
||||
|
@ -547,15 +551,20 @@ ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A) {
|
||||
void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
|
||||
DeclRefExpr *PrivateCopy) {
|
||||
D = getCanonicalDecl(D);
|
||||
if (A == OMPC_threadprivate) {
|
||||
Stack[0].SharingMap[D].Attributes = A;
|
||||
Stack[0].SharingMap[D].RefExpr = E;
|
||||
Stack[0].SharingMap[D].PrivateCopy = nullptr;
|
||||
} else {
|
||||
assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
|
||||
Stack.back().SharingMap[D].Attributes = A;
|
||||
Stack.back().SharingMap[D].RefExpr = E;
|
||||
Stack.back().SharingMap[D].PrivateCopy = PrivateCopy;
|
||||
if (PrivateCopy)
|
||||
addDSA(PrivateCopy->getDecl(), PrivateCopy, A);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -682,6 +691,7 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
|
|||
auto I = std::prev(StartI);
|
||||
if (I->SharingMap.count(D)) {
|
||||
DVar.RefExpr = I->SharingMap[D].RefExpr;
|
||||
DVar.PrivateCopy = I->SharingMap[D].PrivateCopy;
|
||||
DVar.CKind = I->SharingMap[D].Attributes;
|
||||
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
|
||||
}
|
||||
|
@ -886,7 +896,7 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D,
|
|||
return IsByRef;
|
||||
}
|
||||
|
||||
bool Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
|
||||
VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
|
||||
assert(LangOpts.OpenMP && "OpenMP is not allowed");
|
||||
D = getCanonicalDecl(D);
|
||||
|
||||
|
@ -900,18 +910,16 @@ bool Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
|
|||
auto *VD = dyn_cast<VarDecl>(D);
|
||||
if (VD && !VD->hasLocalStorage()) {
|
||||
if (DSAStack->getCurrentDirective() == OMPD_target &&
|
||||
!DSAStack->isClauseParsingMode()) {
|
||||
return true;
|
||||
}
|
||||
!DSAStack->isClauseParsingMode())
|
||||
return VD;
|
||||
if (DSAStack->getCurScope() &&
|
||||
DSAStack->hasDirective(
|
||||
[](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI,
|
||||
SourceLocation Loc) -> bool {
|
||||
return isOpenMPTargetExecutionDirective(K);
|
||||
},
|
||||
false)) {
|
||||
return true;
|
||||
}
|
||||
false))
|
||||
return VD;
|
||||
}
|
||||
|
||||
if (DSAStack->getCurrentDirective() != OMPD_unknown &&
|
||||
|
@ -921,15 +929,16 @@ bool Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
|
|||
(VD && VD->hasLocalStorage() &&
|
||||
isParallelOrTaskRegion(DSAStack->getCurrentDirective())) ||
|
||||
(VD && DSAStack->isForceVarCapturing()))
|
||||
return true;
|
||||
return VD;
|
||||
auto DVarPrivate = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
|
||||
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
|
||||
return true;
|
||||
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
|
||||
DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate, MatchesAlways(),
|
||||
DSAStack->isClauseParsingMode());
|
||||
return DVarPrivate.CKind != OMPC_unknown;
|
||||
if (DVarPrivate.CKind != OMPC_unknown)
|
||||
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
|
||||
}
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) {
|
||||
|
@ -6958,6 +6967,50 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
|
|||
return Res;
|
||||
}
|
||||
|
||||
static DeclRefExpr *buildCapture(Sema &S, IdentifierInfo *Id,
|
||||
Expr *CaptureExpr) {
|
||||
ASTContext &C = S.getASTContext();
|
||||
Expr *Init = CaptureExpr->IgnoreImpCasts();
|
||||
QualType Ty = Init->getType();
|
||||
if (CaptureExpr->getObjectKind() == OK_Ordinary) {
|
||||
if (S.getLangOpts().CPlusPlus)
|
||||
Ty = C.getLValueReferenceType(Ty);
|
||||
else {
|
||||
Ty = C.getPointerType(Ty);
|
||||
ExprResult Res =
|
||||
S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_AddrOf, Init);
|
||||
if (!Res.isUsable())
|
||||
return nullptr;
|
||||
Init = Res.get();
|
||||
}
|
||||
}
|
||||
auto *CFD = OMPCapturedFieldDecl::Create(C, S.CurContext, Id, Ty);
|
||||
S.CurContext->addHiddenDecl(CFD);
|
||||
S.AddInitializerToDecl(CFD, Init, /*DirectInit=*/false,
|
||||
/*TypeMayContainAuto=*/true);
|
||||
return buildDeclRefExpr(S, CFD, Ty.getNonReferenceType(), SourceLocation());
|
||||
}
|
||||
|
||||
ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK,
|
||||
ExprObjectKind OK) {
|
||||
SourceLocation Loc = Capture->getInit()->getExprLoc();
|
||||
ExprResult Res = BuildDeclRefExpr(
|
||||
Capture, Capture->getType().getNonReferenceType(), VK_LValue, Loc);
|
||||
if (!Res.isUsable())
|
||||
return ExprError();
|
||||
if (OK == OK_Ordinary && !getLangOpts().CPlusPlus) {
|
||||
Res = CreateBuiltinUnaryOp(Loc, UO_Deref, Res.get());
|
||||
if (!Res.isUsable())
|
||||
return ExprError();
|
||||
}
|
||||
if (VK != VK_LValue && Res.get()->isGLValue()) {
|
||||
Res = DefaultLvalueConversion(Res.get());
|
||||
if (!Res.isUsable())
|
||||
return ExprError();
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
|
@ -7050,8 +7103,11 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
|
|||
auto VDPrivateRefExpr = buildDeclRefExpr(
|
||||
*this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc);
|
||||
|
||||
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private);
|
||||
Vars.push_back(RefExpr->IgnoreParens());
|
||||
DeclRefExpr *Ref = nullptr;
|
||||
if (!VD)
|
||||
Ref = buildCapture(*this, D->getIdentifier(), RefExpr);
|
||||
DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref);
|
||||
Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref);
|
||||
PrivateCopies.push_back(VDPrivateRefExpr);
|
||||
}
|
||||
|
||||
|
|
|
@ -2483,6 +2483,11 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
|
|||
return TD;
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitOMPCapturedFieldDecl(
|
||||
OMPCapturedFieldDecl * /*D*/) {
|
||||
llvm_unreachable("Should not be met in templates");
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
|
||||
return VisitFunctionDecl(D, nullptr);
|
||||
}
|
||||
|
|
|
@ -329,6 +329,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
|
|||
case Decl::ClassScopeFunctionSpecialization:
|
||||
case Decl::Import:
|
||||
case Decl::OMPThreadPrivate:
|
||||
case Decl::OMPCapturedField:
|
||||
case Decl::BuiltinTemplate:
|
||||
return false;
|
||||
|
||||
|
|
|
@ -350,6 +350,7 @@ namespace clang {
|
|||
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
|
||||
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
||||
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
|
||||
void VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D);
|
||||
|
||||
/// We've merged the definition \p MergedDef into the existing definition
|
||||
/// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made
|
||||
|
@ -2360,6 +2361,10 @@ void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
|
|||
D->setVars(Vars);
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D) {
|
||||
VisitVarDecl(D);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Attribute Reading
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -3323,6 +3328,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
|||
case DECL_OMP_THREADPRIVATE:
|
||||
D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]);
|
||||
break;
|
||||
case DECL_OMP_CAPTUREDFIELD:
|
||||
D = OMPCapturedFieldDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
case DECL_EMPTY:
|
||||
D = EmptyDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
|
|
|
@ -131,6 +131,7 @@ namespace clang {
|
|||
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
|
||||
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
||||
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
|
||||
void VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D);
|
||||
|
||||
/// Add an Objective-C type parameter list to the given record.
|
||||
void AddObjCTypeParamList(ObjCTypeParamList *typeParams) {
|
||||
|
@ -1628,6 +1629,11 @@ void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
|
|||
Code = serialization::DECL_OMP_THREADPRIVATE;
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D) {
|
||||
VisitVarDecl(D);
|
||||
Code = serialization::DECL_OMP_CAPTUREDFIELD;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ASTWriter Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -18,11 +18,69 @@ struct S {
|
|||
|
||||
volatile int g __attribute__((aligned(128))) = 1212;
|
||||
|
||||
struct SS {
|
||||
int a;
|
||||
int b : 4;
|
||||
int &c;
|
||||
SS(int &d) : a(0), b(0), c(d) {
|
||||
#pragma omp parallel private(a, b, c)
|
||||
#ifdef LAMBDA
|
||||
[&]() {
|
||||
++this->a, --b, (this)->c /= 1;
|
||||
#pragma omp parallel private(a, b, c)
|
||||
++(this)->a, --b, this->c /= 1;
|
||||
}();
|
||||
#elif defined(BLOCKS)
|
||||
^{
|
||||
++a;
|
||||
--this->b;
|
||||
(this)->c /= 1;
|
||||
#pragma omp parallel private(a, b, c)
|
||||
++(this)->a, --b, this->c /= 1;
|
||||
}();
|
||||
#else
|
||||
++this->a, --b, c /= 1;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SST {
|
||||
T a;
|
||||
SST() : a(T()) {
|
||||
#pragma omp parallel private(a)
|
||||
#ifdef LAMBDA
|
||||
[&]() {
|
||||
[&]() {
|
||||
++this->a;
|
||||
#pragma omp parallel private(a)
|
||||
++(this)->a;
|
||||
}();
|
||||
}();
|
||||
#elif defined(BLOCKS)
|
||||
^{
|
||||
^{
|
||||
++a;
|
||||
#pragma omp parallel private(a)
|
||||
++(this)->a;
|
||||
}();
|
||||
}();
|
||||
#else
|
||||
++(this)->a;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// CHECK: [[SS_TY:%.+]] = type { i{{[0-9]+}}, i8
|
||||
// LAMBDA: [[SS_TY:%.+]] = type { i{{[0-9]+}}, i8
|
||||
// BLOCKS: [[SS_TY:%.+]] = type { i{{[0-9]+}}, i8
|
||||
// CHECK: [[S_FLOAT_TY:%.+]] = type { float }
|
||||
// CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} }
|
||||
// CHECK: [[SST_TY:%.+]] = type { i{{[0-9]+}} }
|
||||
template <typename T>
|
||||
T tmain() {
|
||||
S<T> test;
|
||||
SST<T> sst;
|
||||
T t_var __attribute__((aligned(128))) = T();
|
||||
T vec[] __attribute__((aligned(128))) = {1, 2};
|
||||
S<T> s_arr[] __attribute__((aligned(128))) = {1, 2};
|
||||
|
@ -37,9 +95,11 @@ T tmain() {
|
|||
|
||||
int main() {
|
||||
static int sivar;
|
||||
SS ss(sivar);
|
||||
#ifdef LAMBDA
|
||||
// LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212,
|
||||
// LAMBDA-LABEL: @main
|
||||
// LAMBDA: call
|
||||
// LAMBDA: call{{.*}} void [[OUTER_LAMBDA:@.+]](
|
||||
[&]() {
|
||||
// LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
|
||||
|
@ -47,6 +107,36 @@ int main() {
|
|||
// LAMBDA: call{{.*}} void {{.+}} @__kmpc_fork_call({{.+}}, i32 0, {{.+}}* [[OMP_REGION:@.+]] to {{.+}})
|
||||
#pragma omp parallel private(g, sivar)
|
||||
{
|
||||
// LAMBDA: define {{.+}} @{{.+}}([[SS_TY]]* %
|
||||
// LAMBDA: store i{{[0-9]+}} 0, i{{[0-9]+}}* %
|
||||
// LAMBDA: store i8
|
||||
// LAMBDA: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void
|
||||
// LAMBDA: ret
|
||||
|
||||
// LAMBDA: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}})
|
||||
// LAMBDA-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %
|
||||
// LAMBDA: call{{.*}} void
|
||||
// LAMBDA: ret void
|
||||
|
||||
// LAMBDA: define internal void @{{.+}}(i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}})
|
||||
// LAMBDA: [[A_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// LAMBDA: [[B_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// LAMBDA: [[C_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// LAMBDA: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]],
|
||||
// LAMBDA: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]],
|
||||
// LAMBDA-NEXT: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFA]],
|
||||
// LAMBDA-NEXT: [[A_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[A_PRIV]],
|
||||
// LAMBDA-NEXT: [[INC:%.+]] = add nsw i{{[0-9]+}} [[A_VAL]], 1
|
||||
// LAMBDA-NEXT: store i{{[0-9]+}} [[INC]], i{{[0-9]+}}* [[A_PRIV]],
|
||||
// LAMBDA-NEXT: [[B_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[B_PRIV]],
|
||||
// LAMBDA-NEXT: [[DEC:%.+]] = add nsw i{{[0-9]+}} [[B_VAL]], -1
|
||||
// LAMBDA-NEXT: store i{{[0-9]+}} [[DEC]], i{{[0-9]+}}* [[B_PRIV]],
|
||||
// LAMBDA-NEXT: [[C_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFC]],
|
||||
// LAMBDA-NEXT: [[C_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[C_PRIV]],
|
||||
// LAMBDA-NEXT: [[DIV:%.+]] = sdiv i{{[0-9]+}} [[C_VAL]], 1
|
||||
// LAMBDA-NEXT: store i{{[0-9]+}} [[DIV]], i{{[0-9]+}}* [[C_PRIV]],
|
||||
// LAMBDA-NEXT: ret void
|
||||
|
||||
// LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* noalias %{{.+}}, i32* noalias %{{.+}})
|
||||
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
|
||||
// LAMBDA: [[SIVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}},
|
||||
|
@ -80,6 +170,7 @@ int main() {
|
|||
#elif defined(BLOCKS)
|
||||
// BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212,
|
||||
// BLOCKS-LABEL: @main
|
||||
// BLOCKS: call
|
||||
// BLOCKS: call{{.*}} void {{%.+}}(i8
|
||||
^{
|
||||
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
|
||||
|
@ -116,6 +207,35 @@ int main() {
|
|||
}
|
||||
}();
|
||||
return 0;
|
||||
// BLOCKS: define {{.+}} @{{.+}}([[SS_TY]]* %
|
||||
// BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* %
|
||||
// BLOCKS: store i8
|
||||
// BLOCKS: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void
|
||||
// BLOCKS: ret
|
||||
|
||||
// BLOCKS: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}})
|
||||
// BLOCKS-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %
|
||||
// BLOCKS: call{{.*}} void
|
||||
// BLOCKS: ret void
|
||||
|
||||
// BLOCKS: define internal void @{{.+}}(i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}})
|
||||
// BLOCKS: [[A_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// BLOCKS: [[B_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// BLOCKS: [[C_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// BLOCKS: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]],
|
||||
// BLOCKS: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]],
|
||||
// BLOCKS-NEXT: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFA]],
|
||||
// BLOCKS-NEXT: [[A_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[A_PRIV]],
|
||||
// BLOCKS-NEXT: [[INC:%.+]] = add nsw i{{[0-9]+}} [[A_VAL]], 1
|
||||
// BLOCKS-NEXT: store i{{[0-9]+}} [[INC]], i{{[0-9]+}}* [[A_PRIV]],
|
||||
// BLOCKS-NEXT: [[B_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[B_PRIV]],
|
||||
// BLOCKS-NEXT: [[DEC:%.+]] = add nsw i{{[0-9]+}} [[B_VAL]], -1
|
||||
// BLOCKS-NEXT: store i{{[0-9]+}} [[DEC]], i{{[0-9]+}}* [[B_PRIV]],
|
||||
// BLOCKS-NEXT: [[C_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFC]],
|
||||
// BLOCKS-NEXT: [[C_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[C_PRIV]],
|
||||
// BLOCKS-NEXT: [[DIV:%.+]] = sdiv i{{[0-9]+}} [[C_VAL]], 1
|
||||
// BLOCKS-NEXT: store i{{[0-9]+}} [[DIV]], i{{[0-9]+}}* [[C_PRIV]],
|
||||
// BLOCKS-NEXT: ret void
|
||||
#else
|
||||
S<float> test;
|
||||
int t_var = 0;
|
||||
|
@ -166,6 +286,31 @@ int main() {
|
|||
// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
|
||||
// CHECK: ret
|
||||
//
|
||||
// CHECK: define {{.+}} @{{.+}}([[SS_TY]]* %
|
||||
// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* %
|
||||
// CHECK: store i8
|
||||
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void
|
||||
// CHECK: ret
|
||||
|
||||
// CHECK: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}})
|
||||
// CHECK: [[A_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// CHECK: [[B_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// CHECK: [[C_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// CHECK: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]],
|
||||
// CHECK: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]],
|
||||
// CHECK-NEXT: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFA]],
|
||||
// CHECK-NEXT: [[A_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[A_PRIV]],
|
||||
// CHECK-NEXT: [[INC:%.+]] = add nsw i{{[0-9]+}} [[A_VAL]], 1
|
||||
// CHECK-NEXT: store i{{[0-9]+}} [[INC]], i{{[0-9]+}}* [[A_PRIV]],
|
||||
// CHECK-NEXT: [[B_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[B_PRIV]],
|
||||
// CHECK-NEXT: [[DEC:%.+]] = add nsw i{{[0-9]+}} [[B_VAL]], -1
|
||||
// CHECK-NEXT: store i{{[0-9]+}} [[DEC]], i{{[0-9]+}}* [[B_PRIV]],
|
||||
// CHECK-NEXT: [[C_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFC]],
|
||||
// CHECK-NEXT: [[C_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[C_PRIV]],
|
||||
// CHECK-NEXT: [[DIV:%.+]] = sdiv i{{[0-9]+}} [[C_VAL]], 1
|
||||
// CHECK-NEXT: store i{{[0-9]+}} [[DIV]], i{{[0-9]+}}* [[C_PRIV]],
|
||||
// CHECK-NEXT: ret void
|
||||
|
||||
// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}})
|
||||
// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}}, align 128
|
||||
// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], align 128
|
||||
|
@ -184,5 +329,20 @@ int main() {
|
|||
// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
|
||||
// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]*
|
||||
// CHECK: ret void
|
||||
|
||||
// CHECK: define {{.+}} @{{.+}}([[SST_TY]]* %
|
||||
// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* %
|
||||
// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SST_TY]]*)* [[SST_MICROTASK:@.+]] to void
|
||||
// CHECK: ret
|
||||
|
||||
// CHECK: define internal void [[SST_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SST_TY]]* %{{.+}})
|
||||
// CHECK: [[A_PRIV:%.+]] = alloca i{{[0-9]+}},
|
||||
// CHECK: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REF:%.+]],
|
||||
// CHECK-NEXT: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REF]],
|
||||
// CHECK-NEXT: [[A_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[A_PRIV]],
|
||||
// CHECK-NEXT: [[INC:%.+]] = add nsw i{{[0-9]+}} [[A_VAL]], 1
|
||||
// CHECK-NEXT: store i{{[0-9]+}} [[INC]], i{{[0-9]+}}* [[A_PRIV]],
|
||||
// CHECK-NEXT: ret void
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -5669,6 +5669,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
|
|||
case Decl::StaticAssert:
|
||||
case Decl::Block:
|
||||
case Decl::Captured:
|
||||
case Decl::OMPCapturedField:
|
||||
case Decl::Label: // FIXME: Is this right??
|
||||
case Decl::ClassScopeFunctionSpecialization:
|
||||
case Decl::Import:
|
||||
|
|
Loading…
Reference in New Issue