Skip to content

Commit befb4be

Browse files
committed
[OpenMP] omp begin/end declare variant - part 2, sema ("+CG")
This is the second part loosely extracted from D71179 and cleaned up. This patch provides semantic analysis support for `omp begin/end declare variant`, mostly as defined in OpenMP technical report 8 (TR8) [0]. The sema handling makes code generation obsolete as we generate "the right" calls that can just be handled as usual. This handling also applies to the existing, albeit problematic, `omp declare variant support`. As a consequence a lot of unneeded code generation and complexity is removed. A major purpose of this patch is to provide proper `math.h`/`cmath` support for OpenMP target offloading. See PR42061, PR42798, PR42799. The current code was developed with this feature in mind, see [1]. The logic is as follows: If we have seen a `#pragma omp begin declare variant match(<SELECTOR>)` but not the corresponding `end declare variant`, and we find a function definition we will: 1) Create a function declaration for the definition we were about to generate. 2) Create a function definition but with a mangled name (according to `<SELECTOR>`). 3) Annotate the declaration with the `OMPDeclareVariantAttr`, the same one used already for `omp declare variant`, using and the mangled function definition as specialization for the context defined by `<SELECTOR>`. When a call is created we inspect it. If the target has an `OMPDeclareVariantAttr` attribute we try to specialize the call. To this end, all variants are checked, the best applicable one is picked and a new call to the specialization is created. The new call is used instead of the original one to the base function. To keep the AST printing and tooling possible we utilize the PseudoObjectExpr. The original call is the syntactic expression, the specialized call is the semantic expression. [0] https://www.openmp.org/wp-content/uploads/openmp-TR8.pdf [1] https://reviews.llvm.org/D61399#change-496lQkg0mhRN Reviewers: kiranchandramohan, ABataev, RaviNarayanaswamy, gtbercea, grokos, sdmitriev, JonChesterfield, hfinkel, fghanim, aaron.ballman Subscribers: bollu, guansong, openmp-commits, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D75779
1 parent 095cecb commit befb4be

File tree

46 files changed

+1726
-564
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1726
-564
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4542,6 +4542,13 @@ inline bool IsEnumDeclScoped(EnumDecl *ED) {
45424542
return ED->isScoped();
45434543
}
45444544

4545+
/// OpenMP variants are mangled early based on their OpenMP context selector.
4546+
/// The new name looks likes this:
4547+
/// <name> + OpenMPVariantManglingSeparatorStr + <mangled OpenMP context>
4548+
static constexpr StringRef getOpenMPVariantManglingSeparatorStr() {
4549+
return ".ompvariant";
4550+
}
4551+
45454552
} // namespace clang
45464553

45474554
#endif // LLVM_CLANG_AST_DECL_H

clang/include/clang/AST/OpenMPClause.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7146,6 +7146,9 @@ class OMPTraitInfo {
71467146
friend class ASTContext;
71477147

71487148
public:
7149+
/// Reconstruct a (partial) OMPTraitInfo object from a mangled name.
7150+
OMPTraitInfo(StringRef MangledName);
7151+
71497152
struct OMPTraitProperty {
71507153
llvm::omp::TraitProperty Kind = llvm::omp::TraitProperty::invalid;
71517154
};
@@ -7184,6 +7187,9 @@ class OMPTraitInfo {
71847187
llvm::omp::VariantMatchInfo &VMI,
71857188
bool DeviceSetOnly) const;
71867189

7190+
/// Return a string representation identifying this context selector.
7191+
std::string getMangledName() const;
7192+
71877193
/// Print a human readable representation into \p OS.
71887194
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
71897195
};

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,9 @@ def err_omp_declare_simd_inbranch_notinbranch : Error<
12341234
"unexpected '%0' clause, '%1' is specified already">;
12351235
def err_expected_end_declare_target_or_variant : Error<
12361236
"expected '#pragma omp end declare %select{target|variant}0'">;
1237+
def err_expected_begin_declare_variant
1238+
: Error<"'#pragma omp end declare variant' with no matching '#pragma omp "
1239+
"begin declare variant'">;
12371240
def err_omp_declare_target_unexpected_clause: Error<
12381241
"unexpected '%0' clause, only %select{'to' or 'link'|'to', 'link' or 'device_type'}1 clauses expected">;
12391242
def err_omp_expected_clause: Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10186,6 +10186,10 @@ def err_omp_non_lvalue_in_map_or_motion_clauses: Error<
1018610186
>;
1018710187
def err_omp_event_var_expected : Error<
1018810188
"expected variable of the 'omp_event_handle_t' type%select{|, not %1}0">;
10189+
def warn_nested_declare_variant
10190+
: Warning<"nesting `omp begin/end declare variant` is not supported yet; "
10191+
"nested context ignored">,
10192+
InGroup<SourceUsesOpenMP>;
1018910193
} // end of OpenMP category
1019010194

1019110195
let CategoryName = "Related Result Type Issue" in {

clang/include/clang/Basic/IdentifierTable.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
108108
// True if this is the 'import' contextual keyword.
109109
unsigned IsModulesImport : 1;
110110

111-
// 29 bits left in a 64-bit word.
111+
// True if this is a mangled OpenMP variant name.
112+
unsigned IsMangledOpenMPVariantName : 1;
113+
114+
// 28 bits left in a 64-bit word.
112115

113116
// Managed by the language front-end.
114117
void *FETokenInfo = nullptr;
@@ -121,7 +124,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
121124
IsPoisoned(false), IsCPPOperatorKeyword(false),
122125
NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false),
123126
FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false),
124-
IsModulesImport(false) {}
127+
IsModulesImport(false), IsMangledOpenMPVariantName(false) {}
125128

126129
public:
127130
IdentifierInfo(const IdentifierInfo &) = delete;
@@ -371,6 +374,12 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
371374
RecomputeNeedsHandleIdentifier();
372375
}
373376

377+
/// Determine whether this is the mangled name of an OpenMP variant.
378+
bool isMangledOpenMPVariantName() const { return IsMangledOpenMPVariantName; }
379+
380+
/// Set whether this is the mangled name of an OpenMP variant.
381+
void setMangledOpenMPVariantName(bool I) { IsMangledOpenMPVariantName = I; }
382+
374383
/// Return true if this identifier is an editor placeholder.
375384
///
376385
/// Editor placeholders are produced by the code-completion engine and are

clang/include/clang/Sema/Sema.h

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9812,14 +9812,55 @@ class Sema final {
98129812
MapT &Map, unsigned Selector = 0,
98139813
SourceRange SrcRange = SourceRange());
98149814

9815-
/// Marks all the functions that might be required for the currently active
9816-
/// OpenMP context.
9817-
void markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
9818-
FunctionDecl *Func,
9819-
bool MightBeOdrUse);
9815+
/// Helper to keep information about the current `omp begin/end declare
9816+
/// variant` nesting.
9817+
struct OMPDeclareVariantScope {
9818+
/// The associated OpenMP context selector.
9819+
OMPTraitInfo *TI;
9820+
9821+
/// The associated OpenMP context selector mangling.
9822+
std::string NameSuffix;
9823+
9824+
OMPDeclareVariantScope(OMPTraitInfo &TI)
9825+
: TI(&TI), NameSuffix(TI.getMangledName()) {}
9826+
};
9827+
9828+
/// The current `omp begin/end declare variant` scopes.
9829+
SmallVector<OMPDeclareVariantScope, 4> OMPDeclareVariantScopes;
9830+
9831+
/// The declarator \p D defines a function in the scope \p S which is nested
9832+
/// in an `omp begin/end declare variant` scope. In this method we create a
9833+
/// declaration for \p D and rename \p D according to the OpenMP context
9834+
/// selector of the surrounding scope.
9835+
FunctionDecl *
9836+
ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S,
9837+
Declarator &D);
9838+
9839+
/// Register \p FD as specialization of \p BaseFD in the current `omp
9840+
/// begin/end declare variant` scope.
9841+
void ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(
9842+
FunctionDecl *FD, FunctionDecl *BaseFD);
98209843

98219844
public:
9822-
/// Struct to store the context selectors info for declare variant directive.
9845+
9846+
/// Can we exit a scope at the moment.
9847+
bool isInOpenMPDeclareVariantScope() {
9848+
return !OMPDeclareVariantScopes.empty();
9849+
}
9850+
9851+
/// Given the potential call expression \p Call, determine if there is a
9852+
/// specialization via the OpenMP declare variant mechanism available. If
9853+
/// there is, return the specialized call expression, otherwise return the
9854+
/// original \p Call.
9855+
ExprResult ActOnOpenMPCall(Sema &S, ExprResult Call, Scope *Scope,
9856+
SourceLocation LParenLoc, MultiExprArg ArgExprs,
9857+
SourceLocation RParenLoc, Expr *ExecConfig);
9858+
9859+
/// Handle a `omp begin declare variant`.
9860+
void ActOnOpenMPBeginDeclareVariant(SourceLocation Loc, OMPTraitInfo &TI);
9861+
9862+
/// Handle a `omp end declare variant`.
9863+
void ActOnOpenMPEndDeclareVariant();
98239864

98249865
/// Checks if the variant/multiversion functions are compatible.
98259866
bool areMultiversionVariantFunctionsCompatible(

clang/lib/AST/DeclarationName.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/DeclBase.h"
1818
#include "clang/AST/DeclCXX.h"
1919
#include "clang/AST/DeclTemplate.h"
20+
#include "clang/AST/OpenMPClause.h"
2021
#include "clang/AST/PrettyPrinter.h"
2122
#include "clang/AST/Type.h"
2223
#include "clang/AST/TypeLoc.h"
@@ -138,8 +139,19 @@ void DeclarationName::print(raw_ostream &OS,
138139
const PrintingPolicy &Policy) const {
139140
switch (getNameKind()) {
140141
case DeclarationName::Identifier:
141-
if (const IdentifierInfo *II = getAsIdentifierInfo())
142-
OS << II->getName();
142+
if (const IdentifierInfo *II = getAsIdentifierInfo()) {
143+
StringRef Name = II->getName();
144+
// If this is a mangled OpenMP variant name we strip off the mangling for
145+
// printing. It should not be visible to the user at all.
146+
if (II->isMangledOpenMPVariantName()) {
147+
std::pair<StringRef, StringRef> NameContextPair =
148+
Name.split(getOpenMPVariantManglingSeparatorStr());
149+
OS << NameContextPair.first << "["
150+
<< OMPTraitInfo(NameContextPair.second) << "]";
151+
} else {
152+
OS << Name;
153+
}
154+
}
143155
return;
144156

145157
case DeclarationName::ObjCZeroArgSelector:

clang/lib/AST/OpenMPClause.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,63 @@ void OMPTraitInfo::print(llvm::raw_ostream &OS,
19671967
}
19681968
}
19691969

1970+
std::string OMPTraitInfo::getMangledName() const {
1971+
std::string MangledName;
1972+
llvm::raw_string_ostream OS(MangledName);
1973+
for (const OMPTraitInfo::OMPTraitSet &Set : Sets) {
1974+
OS << '.' << 'S' << unsigned(Set.Kind);
1975+
for (const OMPTraitInfo::OMPTraitSelector &Selector : Set.Selectors) {
1976+
1977+
bool AllowsTraitScore = false;
1978+
bool RequiresProperty = false;
1979+
isValidTraitSelectorForTraitSet(
1980+
Selector.Kind, Set.Kind, AllowsTraitScore, RequiresProperty);
1981+
OS << '.' << 's' << unsigned(Selector.Kind);
1982+
1983+
if (!RequiresProperty ||
1984+
Selector.Kind == TraitSelector::user_condition)
1985+
continue;
1986+
1987+
for (const OMPTraitInfo::OMPTraitProperty &Property : Selector.Properties)
1988+
OS << '.' << 'P'
1989+
<< getOpenMPContextTraitPropertyName(Property.Kind);
1990+
}
1991+
}
1992+
return OS.str();
1993+
}
1994+
1995+
OMPTraitInfo::OMPTraitInfo(StringRef MangledName) {
1996+
unsigned long U;
1997+
do {
1998+
if (!MangledName.consume_front(".S"))
1999+
break;
2000+
if (MangledName.consumeInteger(10, U))
2001+
break;
2002+
Sets.push_back(OMPTraitSet());
2003+
OMPTraitSet &Set = Sets.back();
2004+
Set.Kind = TraitSet(U);
2005+
do {
2006+
if (!MangledName.consume_front(".s"))
2007+
break;
2008+
if (MangledName.consumeInteger(10, U))
2009+
break;
2010+
Set.Selectors.push_back(OMPTraitSelector());
2011+
OMPTraitSelector &Selector = Set.Selectors.back();
2012+
Selector.Kind = TraitSelector(U);
2013+
do {
2014+
if (!MangledName.consume_front(".P"))
2015+
break;
2016+
Selector.Properties.push_back(OMPTraitProperty());
2017+
OMPTraitProperty &Property = Selector.Properties.back();
2018+
std::pair<StringRef, StringRef> PropRestPair = MangledName.split('.');
2019+
Property.Kind =
2020+
getOpenMPContextTraitPropertyKind(Set.Kind, PropRestPair.first);
2021+
MangledName = PropRestPair.second;
2022+
} while (true);
2023+
} while (true);
2024+
} while (true);
2025+
}
2026+
19702027
llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS,
19712028
const OMPTraitInfo &TI) {
19722029
LangOptions LO;

clang/lib/CodeGen/CGOpenMPRuntime.cpp

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,52 +1275,6 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
12751275
loadOffloadInfoMetadata();
12761276
}
12771277

1278-
bool CGOpenMPRuntime::tryEmitDeclareVariant(const GlobalDecl &NewGD,
1279-
const GlobalDecl &OldGD,
1280-
llvm::GlobalValue *OrigAddr,
1281-
bool IsForDefinition) {
1282-
// Emit at least a definition for the aliasee if the the address of the
1283-
// original function is requested.
1284-
if (IsForDefinition || OrigAddr)
1285-
(void)CGM.GetAddrOfGlobal(NewGD);
1286-
StringRef NewMangledName = CGM.getMangledName(NewGD);
1287-
llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName);
1288-
if (Addr && !Addr->isDeclaration()) {
1289-
const auto *D = cast<FunctionDecl>(OldGD.getDecl());
1290-
const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(NewGD);
1291-
llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI);
1292-
1293-
// Create a reference to the named value. This ensures that it is emitted
1294-
// if a deferred decl.
1295-
llvm::GlobalValue::LinkageTypes LT = CGM.getFunctionLinkage(OldGD);
1296-
1297-
// Create the new alias itself, but don't set a name yet.
1298-
auto *GA =
1299-
llvm::GlobalAlias::create(DeclTy, 0, LT, "", Addr, &CGM.getModule());
1300-
1301-
if (OrigAddr) {
1302-
assert(OrigAddr->isDeclaration() && "Expected declaration");
1303-
1304-
GA->takeName(OrigAddr);
1305-
OrigAddr->replaceAllUsesWith(
1306-
llvm::ConstantExpr::getBitCast(GA, OrigAddr->getType()));
1307-
OrigAddr->eraseFromParent();
1308-
} else {
1309-
GA->setName(CGM.getMangledName(OldGD));
1310-
}
1311-
1312-
// Set attributes which are particular to an alias; this is a
1313-
// specialization of the attributes which may be set on a global function.
1314-
if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() ||
1315-
D->isWeakImported())
1316-
GA->setLinkage(llvm::Function::WeakAnyLinkage);
1317-
1318-
CGM.SetCommonAttributes(OldGD, GA);
1319-
return true;
1320-
}
1321-
return false;
1322-
}
1323-
13241278
void CGOpenMPRuntime::clear() {
13251279
InternalVars.clear();
13261280
// Clean non-target variable declarations possibly used only in debug info.
@@ -1334,14 +1288,6 @@ void CGOpenMPRuntime::clear() {
13341288
continue;
13351289
GV->eraseFromParent();
13361290
}
1337-
// Emit aliases for the deferred aliasees.
1338-
for (const auto &Pair : DeferredVariantFunction) {
1339-
StringRef MangledName = CGM.getMangledName(Pair.second.second);
1340-
llvm::GlobalValue *Addr = CGM.GetGlobalValue(MangledName);
1341-
// If not able to emit alias, just emit original declaration.
1342-
(void)tryEmitDeclareVariant(Pair.second.first, Pair.second.second, Addr,
1343-
/*IsForDefinition=*/false);
1344-
}
13451291
}
13461292

13471293
std::string CGOpenMPRuntime::getName(ArrayRef<StringRef> Parts) const {
@@ -11393,57 +11339,6 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
1139311339
return Address(Addr, Align);
1139411340
}
1139511341

11396-
/// Finds the variant function that matches current context with its context
11397-
/// selector.
11398-
static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM,
11399-
const FunctionDecl *FD) {
11400-
if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
11401-
return FD;
11402-
11403-
SmallVector<Expr *, 8> VariantExprs;
11404-
SmallVector<VariantMatchInfo, 8> VMIs;
11405-
for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
11406-
const OMPTraitInfo &TI = *A->getTraitInfos();
11407-
VMIs.push_back(VariantMatchInfo());
11408-
TI.getAsVariantMatchInfo(CGM.getContext(), VMIs.back(),
11409-
/* DeviceSetOnly */ false);
11410-
VariantExprs.push_back(A->getVariantFuncRef());
11411-
}
11412-
11413-
OMPContext Ctx(CGM.getLangOpts().OpenMPIsDevice, CGM.getTriple());
11414-
// FIXME: Keep the context in the OMPIRBuilder so we can add constructs as we
11415-
// build them.
11416-
11417-
int BestMatchIdx = getBestVariantMatchForContext(VMIs, Ctx);
11418-
if (BestMatchIdx < 0)
11419-
return FD;
11420-
11421-
return cast<FunctionDecl>(
11422-
cast<DeclRefExpr>(VariantExprs[BestMatchIdx]->IgnoreParenImpCasts())
11423-
->getDecl());
11424-
}
11425-
11426-
bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
11427-
const auto *D = cast<FunctionDecl>(GD.getDecl());
11428-
// If the original function is defined already, use its definition.
11429-
StringRef MangledName = CGM.getMangledName(GD);
11430-
llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName);
11431-
if (Orig && !Orig->isDeclaration())
11432-
return false;
11433-
const FunctionDecl *NewFD = getDeclareVariantFunction(CGM, D);
11434-
// Emit original function if it does not have declare variant attribute or the
11435-
// context does not match.
11436-
if (NewFD == D)
11437-
return false;
11438-
GlobalDecl NewGD = GD.getWithDecl(NewFD);
11439-
if (tryEmitDeclareVariant(NewGD, GD, Orig, IsForDefinition)) {
11440-
DeferredVariantFunction.erase(D);
11441-
return true;
11442-
}
11443-
DeferredVariantFunction.insert(std::make_pair(D, std::make_pair(NewGD, GD)));
11444-
return true;
11445-
}
11446-
1144711342
CGOpenMPRuntime::NontemporalDeclsRAII::NontemporalDeclsRAII(
1144811343
CodeGenModule &CGM, const OMPLoopDirective &S)
1144911344
: CGM(CGM), NeedToPush(S.hasClausesOfKind<OMPNontemporalClause>()) {

0 commit comments

Comments
 (0)