Skip to content

Commit

Permalink
[OPENMP5.0]Introduce attribute for declare variant directive.
Browse files Browse the repository at this point in the history
Added attribute for declare variant directive. It will allow to handle
declare variant directive at the codegen and will allow to add extra
checks.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@372147 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
alexey-bataev committed Sep 17, 2019
1 parent 2020458 commit de14442
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 1 deletion.
23 changes: 23 additions & 0 deletions include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -3265,6 +3265,29 @@ def OMPAllocateDecl : InheritableAttr {
let Documentation = [Undocumented];
}

def OMPDeclareVariant : Attr {
let Spellings = [Pragma<"omp", "declare variant">];
let Subjects = SubjectList<[Function]>;
let SemaHandler = 0;
let HasCustomParsing = 1;
let Documentation = [OMPDeclareVariantDocs];
let Args = [
ExprArgument<"VariantFuncRef">
];
let AdditionalMembers = [{
void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
const {
if (const Expr *E = getVariantFuncRef()) {
OS << "(";
E->printPretty(OS, nullptr, Policy);
OS << ")";
}
// TODO: add printing of real context selectors.
OS << " match(unknown={})";
}
}];
}

def InternalLinkage : InheritableAttr {
let Spellings = [Clang<"internal_linkage">];
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
Expand Down
28 changes: 28 additions & 0 deletions include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3208,6 +3208,34 @@ where clause is one of the following:
}];
}

def OMPDeclareVariantDocs : Documentation {
let Category = DocCatFunction;
let Heading = "#pragma omp declare variant";
let Content = [{
The `declare variant` directive declares a specialized variant of a base
function and specifies the context in which that specialized variant is used.
The declare variant directive is a declarative directive.
The syntax of the `declare variant` construct is as follows:

.. code-block:: none

#pragma omp declare variant(variant-func-id) clause new-line
[#pragma omp declare variant(variant-func-id) clause new-line]
[...]
function definition or declaration

where clause is one of the following:

.. code-block:: none

match(context-selector-specification)

and where `variant-func-id` is the name of a function variant that is either a
base language identifier or, for C++, a template-id.

}];
}

def NoStackProtectorDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
4 changes: 4 additions & 0 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -9429,6 +9429,10 @@ def err_omp_declare_variant_diff : Error<
def err_omp_declare_variant_incompat_types : Error<
"variant in '#pragma omp declare variant' with type %0 is incompatible with type %1"
>;
def warn_omp_declare_variant_marked_as_declare_variant : Warning<
"variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'"
>, InGroup<SourceUsesOpenMP>;
def note_omp_marked_declare_variant_here : Note<"marked as 'declare variant' here">;
} // end of OpenMP category

let CategoryName = "Related Result Type Issue" in {
Expand Down
6 changes: 6 additions & 0 deletions include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -9089,6 +9089,12 @@ class Sema {
MapT &Map, unsigned Selector = 0,
SourceRange SrcRange = SourceRange());

/// Marks all the functions that might be required for the currently active
/// OpenMP context.
void markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
FunctionDecl *Func,
bool MightBeOdrUse);

public:
/// Checks if the variant/multiversion functions are compatible.
bool areMultiversionVariantFunctionsCompatible(
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15497,6 +15497,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
}

if (LangOpts.OpenMP) {
markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse);
if (LangOpts.OpenMPIsDevice)
checkOpenMPDeviceFunction(Loc, Func);
else
Expand Down
38 changes: 37 additions & 1 deletion lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4945,8 +4945,12 @@ Sema::ActOnOpenMPDeclareVariantDirective(Sema::DeclGroupPtrTy DG,
// Do not check templates, wait until instantiation.
if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() ||
VariantRef->containsUnexpandedParameterPack() ||
VariantRef->isInstantiationDependent() || FD->isDependentContext())
VariantRef->isInstantiationDependent() || FD->isDependentContext()) {
auto *NewAttr =
OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, SR);
FD->addAttr(NewAttr);
return DG;
}

// Convert VariantRef expression to the type of the original function to
// resolve possible conflicts.
Expand Down Expand Up @@ -5025,6 +5029,17 @@ Sema::ActOnOpenMPDeclareVariantDirective(Sema::DeclGroupPtrTy DG,
return DG;
}

// Check if variant function is not marked with declare variant directive.
if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
Diag(VariantRef->getExprLoc(),
diag::warn_omp_declare_variant_marked_as_declare_variant)
<< VariantRef->getSourceRange();
SourceRange SR =
NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange();
Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR;
return DG;
}

enum DoesntSupport {
VirtFuncs = 1,
Constructors = 3,
Expand Down Expand Up @@ -5087,9 +5102,30 @@ Sema::ActOnOpenMPDeclareVariantDirective(Sema::DeclGroupPtrTy DG,
/*TemplatesSupported=*/true, /*ConstexprSupported=*/false))
return DG;

auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(Context, DRE, SR);
FD->addAttr(NewAttr);
return DG;
}

void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
FunctionDecl *Func,
bool MightBeOdrUse) {
assert(LangOpts.OpenMP && "Expected OpenMP mode.");

if (!Func->isDependentContext() && Func->hasAttrs()) {
for (OMPDeclareVariantAttr *A :
Func->specific_attrs<OMPDeclareVariantAttr>()) {
// TODO: add checks for active OpenMP context where possible.
Expr *VariantRef = A->getVariantFuncRef();
auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
auto *F = cast<FunctionDecl>(DRE->getDecl());
if (!F->isDefined() && F->isTemplateInstantiation())
InstantiateFunctionDefinition(Loc, F->getFirstDecl());
MarkFunctionReferenced(Loc, F, MightBeOdrUse);
}
}
}

StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
Expand Down
49 changes: 49 additions & 0 deletions lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,50 @@ static void instantiateOMPDeclareSimdDeclAttr(
Attr.getRange());
}

/// Instantiation of 'declare variant' attribute and its arguments.
static void instantiateOMPDeclareVariantAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const OMPDeclareVariantAttr &Attr, Decl *New) {
// Allow 'this' in clauses with varlists.
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
New = FTD->getTemplatedDecl();
auto *FD = cast<FunctionDecl>(New);
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());

auto &&SubstExpr = [FD, ThisContext, &S, &TemplateArgs](Expr *E) {
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
Sema::ContextRAII SavedContext(S, FD);
LocalInstantiationScope Local(S);
if (FD->getNumParams() > PVD->getFunctionScopeIndex())
Local.InstantiatedLocal(
PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
return S.SubstExpr(E, TemplateArgs);
}
Sema::CXXThisScopeRAII ThisScope(S, ThisContext, Qualifiers(),
FD->isCXXInstanceMember());
return S.SubstExpr(E, TemplateArgs);
};

// Substitute a single OpenMP clause, which is a potentially-evaluated
// full-expression.
auto &&Subst = [&SubstExpr, &S](Expr *E) {
EnterExpressionEvaluationContext Evaluated(
S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
ExprResult Res = SubstExpr(E);
if (Res.isInvalid())
return Res;
return S.ActOnFinishFullExpr(Res.get(), false);
};

ExprResult VariantFuncRef;
if (Expr *E = Attr.getVariantFuncRef())
VariantFuncRef = Subst(E);

(void)S.ActOnOpenMPDeclareVariantDirective(
S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange());
}

static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) {
Expand Down Expand Up @@ -505,6 +549,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}

if (const auto *OMPAttr = dyn_cast<OMPDeclareVariantAttr>(TmplAttr)) {
instantiateOMPDeclareVariantAttr(*this, TemplateArgs, *OMPAttr, New);
continue;
}

if (const auto *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) {
instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
Expand Down
16 changes: 16 additions & 0 deletions test/OpenMP/declare_variant_ast_print.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// RUN: %clang_cc1 -verify -fopenmp -x c -std=c99 -ast-print %s -o - | FileCheck %s

// RUN: %clang_cc1 -verify -fopenmp-simd -x c -std=c99 -ast-print %s -o - | FileCheck %s

// expected-no-diagnostics

int foo(void);

#pragma omp declare variant(foo) match(xxx={})
#pragma omp declare variant(foo) match(xxx={vvv})
int bar(void);

// CHECK: int foo();
// CHECK-NEXT: #pragma omp declare variant(foo) match(unknown={})
// CHECK-NEXT: #pragma omp declare variant(foo) match(unknown={})
// CHECK-NEXT: int bar();
Loading

0 comments on commit de14442

Please sign in to comment.