Skip to content

Commit 2df5f12

Browse files
committed
[OPENMP50]Initial codegen for declare variant implementation vendor.
Initial implementation of global aliases emission for the declare variant pragma with implementation vendor context selector set. llvm-svn: 373387
1 parent 91b62d5 commit 2df5f12

File tree

4 files changed

+241
-0
lines changed

4 files changed

+241
-0
lines changed

clang/lib/CodeGen/CGOpenMPRuntime.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,51 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
12641264
loadOffloadInfoMetadata();
12651265
}
12661266

1267+
static bool tryEmitAlias(CodeGenModule &CGM, const GlobalDecl &NewGD,
1268+
const GlobalDecl &OldGD, llvm::GlobalValue *OrigAddr,
1269+
bool IsForDefinition) {
1270+
// Emit at least a definition for the aliasee if the the address of the
1271+
// original function is requested.
1272+
if (IsForDefinition || OrigAddr)
1273+
(void)CGM.GetAddrOfGlobal(NewGD);
1274+
StringRef NewMangledName = CGM.getMangledName(NewGD);
1275+
llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName);
1276+
if (Addr && !Addr->isDeclaration()) {
1277+
const auto *D = cast<FunctionDecl>(OldGD.getDecl());
1278+
const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(OldGD);
1279+
llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI);
1280+
1281+
// Create a reference to the named value. This ensures that it is emitted
1282+
// if a deferred decl.
1283+
llvm::GlobalValue::LinkageTypes LT = CGM.getFunctionLinkage(OldGD);
1284+
1285+
// Create the new alias itself, but don't set a name yet.
1286+
auto *GA =
1287+
llvm::GlobalAlias::create(DeclTy, 0, LT, "", Addr, &CGM.getModule());
1288+
1289+
if (OrigAddr) {
1290+
assert(OrigAddr->isDeclaration() && "Expected declaration");
1291+
1292+
GA->takeName(OrigAddr);
1293+
OrigAddr->replaceAllUsesWith(
1294+
llvm::ConstantExpr::getBitCast(GA, OrigAddr->getType()));
1295+
OrigAddr->eraseFromParent();
1296+
} else {
1297+
GA->setName(CGM.getMangledName(OldGD));
1298+
}
1299+
1300+
// Set attributes which are particular to an alias; this is a
1301+
// specialization of the attributes which may be set on a global function.
1302+
if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() ||
1303+
D->isWeakImported())
1304+
GA->setLinkage(llvm::Function::WeakAnyLinkage);
1305+
1306+
CGM.SetCommonAttributes(OldGD, GA);
1307+
return true;
1308+
}
1309+
return false;
1310+
}
1311+
12671312
void CGOpenMPRuntime::clear() {
12681313
InternalVars.clear();
12691314
// Clean non-target variable declarations possibly used only in debug info.
@@ -1277,6 +1322,14 @@ void CGOpenMPRuntime::clear() {
12771322
continue;
12781323
GV->eraseFromParent();
12791324
}
1325+
// Emit aliases for the deferred aliasees.
1326+
for (const auto &Pair : DeferredVariantFunction) {
1327+
StringRef MangledName = CGM.getMangledName(Pair.second.second);
1328+
llvm::GlobalValue *Addr = CGM.GetGlobalValue(MangledName);
1329+
// If not able to emit alias, just emit original declaration.
1330+
(void)tryEmitAlias(CGM, Pair.second.first, Pair.second.second, Addr,
1331+
/*IsForDefinition=*/false);
1332+
}
12801333
}
12811334

12821335
std::string CGOpenMPRuntime::getName(ArrayRef<StringRef> Parts) const {
@@ -11086,6 +11139,80 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
1108611139
return Address(Addr, Align);
1108711140
}
1108811141

11142+
/// Checks current context and returns true if it matches the context selector.
11143+
template <OMPDeclareVariantAttr::CtxSelectorSetType CtxSet,
11144+
OMPDeclareVariantAttr::CtxSelectorType Ctx>
11145+
static bool checkContext(const OMPDeclareVariantAttr *A) {
11146+
assert(CtxSet != OMPDeclareVariantAttr::CtxSetUnknown &&
11147+
Ctx != OMPDeclareVariantAttr::CtxUnknown &&
11148+
"Unknown context selector or context selector set.");
11149+
return false;
11150+
}
11151+
11152+
/// Checks for implementation={vendor(<vendor>)} context selector.
11153+
/// \returns true iff <vendor>="llvm", false otherwise.
11154+
template <>
11155+
bool checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
11156+
OMPDeclareVariantAttr::CtxVendor>(
11157+
const OMPDeclareVariantAttr *A) {
11158+
return !A->getImplVendor().compare("llvm");
11159+
}
11160+
11161+
/// Finds the variant function that matches current context with its context
11162+
/// selector.
11163+
static const FunctionDecl *getDeclareVariantFunction(const FunctionDecl *FD) {
11164+
if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
11165+
return FD;
11166+
// Iterate through all DeclareVariant attributes and check context selectors.
11167+
SmallVector<const OMPDeclareVariantAttr *, 4> MatchingAttributes;
11168+
for (const auto * A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
11169+
switch (A->getCtxSelectorSet()) {
11170+
case OMPDeclareVariantAttr::CtxSetImplementation:
11171+
switch (A->getCtxSelector()) {
11172+
case OMPDeclareVariantAttr::CtxVendor:
11173+
if (checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
11174+
OMPDeclareVariantAttr::CtxVendor>(A))
11175+
MatchingAttributes.push_back(A);
11176+
break;
11177+
case OMPDeclareVariantAttr::CtxUnknown:
11178+
llvm_unreachable(
11179+
"Unknown context selector in implementation selctor set.");
11180+
}
11181+
break;
11182+
case OMPDeclareVariantAttr::CtxSetUnknown:
11183+
llvm_unreachable("Unknown context selector set.");
11184+
}
11185+
}
11186+
if (MatchingAttributes.empty())
11187+
return FD;
11188+
// TODO: implement score analysis of multiple context selectors.
11189+
const OMPDeclareVariantAttr *MainAttr = MatchingAttributes.front();
11190+
return cast<FunctionDecl>(
11191+
cast<DeclRefExpr>(MainAttr->getVariantFuncRef()->IgnoreParenImpCasts())
11192+
->getDecl());
11193+
}
11194+
11195+
bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
11196+
const auto *D = cast<FunctionDecl>(GD.getDecl());
11197+
// If the original function is defined already, use its definition.
11198+
StringRef MangledName = CGM.getMangledName(GD);
11199+
llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName);
11200+
if (Orig && !Orig->isDeclaration())
11201+
return false;
11202+
const FunctionDecl *NewFD = getDeclareVariantFunction(D);
11203+
// Emit original function if it does not have declare variant attribute or the
11204+
// context does not match.
11205+
if (NewFD == D)
11206+
return false;
11207+
GlobalDecl NewGD = GD.getWithDecl(NewFD);
11208+
if (tryEmitAlias(CGM, NewGD, GD, Orig, IsForDefinition)) {
11209+
DeferredVariantFunction.erase(D);
11210+
return true;
11211+
}
11212+
DeferredVariantFunction.insert(std::make_pair(D, std::make_pair(NewGD, GD)));
11213+
return true;
11214+
}
11215+
1108911216
llvm::Function *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction(
1109011217
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
1109111218
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {

clang/lib/CodeGen/CGOpenMPRuntime.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,12 @@ class CGOpenMPRuntime {
644644
/// must be emitted.
645645
llvm::SmallDenseSet<const VarDecl *> DeferredGlobalVariables;
646646

647+
/// Mapping of the original functions to their variants and original global
648+
/// decl.
649+
llvm::MapVector<CanonicalDeclPtr<const FunctionDecl>,
650+
std::pair<GlobalDecl, GlobalDecl>>
651+
DeferredVariantFunction;
652+
647653
/// Flag for keeping track of weather a requires unified_shared_memory
648654
/// directive is present.
649655
bool HasRequiresUnifiedSharedMemory = false;
@@ -1652,6 +1658,9 @@ class CGOpenMPRuntime {
16521658

16531659
/// Return whether the unified_shared_memory has been specified.
16541660
bool hasRequiresUnifiedSharedMemory() const;
1661+
1662+
/// Emits the definition of the declare variant function.
1663+
virtual bool emitDeclareVariant(GlobalDecl GD, bool IsForDefinition);
16551664
};
16561665

16571666
/// Class supports emissionof SIMD-only code.

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,6 +2532,11 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
25322532
return;
25332533
}
25342534

2535+
// Check if this must be emitted as declare variant.
2536+
if (LangOpts.OpenMP && isa<FunctionDecl>(Global) && OpenMPRuntime &&
2537+
OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/false))
2538+
return;
2539+
25352540
// If we're deferring emission of a C++ variable with an
25362541
// initializer, remember the order in which it appeared in the file.
25372542
if (getLangOpts().CPlusPlus && isa<VarDecl>(Global) &&
@@ -3051,6 +3056,10 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
30513056
EmitGlobal(GDDef);
30523057
}
30533058
}
3059+
// Check if this must be emitted as declare variant and emit reference to
3060+
// the the declare variant function.
3061+
if (LangOpts.OpenMP && OpenMPRuntime)
3062+
(void)OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true);
30543063

30553064
if (FD->isMultiVersion()) {
30563065
const auto *TA = FD->getAttr<TargetAttr>();
@@ -4327,6 +4336,11 @@ void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
43274336

43284337
void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
43294338
llvm::GlobalValue *GV) {
4339+
// Check if this must be emitted as declare variant.
4340+
if (LangOpts.OpenMP && OpenMPRuntime &&
4341+
OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true))
4342+
return;
4343+
43304344
const auto *D = cast<FunctionDecl>(GD.getDecl());
43314345

43324346
// Compute the function info and LLVM type.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple %itanium_abi_triple -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fsanitize-address-use-after-scope | FileCheck %s
2+
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -emit-pch -o %t -fopenmp-version=50 %s
3+
// RUN: %clang_cc1 -fopenmp -x c++ -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - -fopenmp-version=50 | FileCheck %s
4+
// expected-no-diagnostics
5+
6+
// CHECK-NOT: ret i32 {{1|4}}
7+
// CHECK-DAG: @_Z3barv = {{.*}}alias i32 (), i32 ()* @_Z3foov
8+
// CHECK-DAG: @_ZN16SpecSpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev
9+
// CHECK-DAG: @_ZN16SpecSpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev
10+
// CHECK-DAG: @_ZN12SpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev
11+
// CHECK-DAG: @_Z4callv = {{.*}}alias i32 (), i32 ()* @_Z4testv
12+
// CHECK-DAG: @_ZL9stat_usedv = internal alias i32 (), i32 ()* @_ZL10stat_used_v
13+
// CHECK-DAG: @_ZN12SpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev
14+
// CHECK-DAG: declare {{.*}}i32 @_Z5bazzzv()
15+
// CHECK-DAG: declare {{.*}}i32 @_Z3bazv()
16+
// CHECK-DAG: ret i32 2
17+
// CHECK-DAG: ret i32 3
18+
// CHECK-DAG: ret i32 5
19+
// CHECK-DAG: ret i32 6
20+
// CHECK-DAG: ret i32 7
21+
// CHECK-NOT: ret i32 {{1|4}}
22+
23+
#ifndef HEADER
24+
#define HEADER
25+
26+
int foo() { return 2; }
27+
28+
#pragma omp declare variant(foo) match(implementation = {vendor(llvm)})
29+
int bar() { return 1; }
30+
31+
int bazzz();
32+
#pragma omp declare variant(bazzz) match(implementation = {vendor(llvm)})
33+
int baz() { return 1; }
34+
35+
int test();
36+
#pragma omp declare variant(test) match(implementation = {vendor(llvm)})
37+
int call() { return 1; }
38+
39+
static int stat_unused_();
40+
#pragma omp declare variant(stat_unused_) match(implementation = {vendor(llvm)})
41+
static int stat_unused() { return 1; }
42+
43+
static int stat_used_();
44+
#pragma omp declare variant(stat_used_) match(implementation = {vendor(llvm)})
45+
static int stat_used() { return 1; }
46+
47+
int main() { return bar() + baz() + call() + stat_used(); }
48+
49+
int test() { return 3; }
50+
static int stat_unused_() { return 4; }
51+
static int stat_used_() { return 5; }
52+
53+
struct SpecialFuncs {
54+
void vd() {}
55+
SpecialFuncs();
56+
~SpecialFuncs();
57+
58+
int method_() { return 6; }
59+
#pragma omp declare variant(SpecialFuncs::method_) \
60+
match(implementation = {vendor(llvm)})
61+
int method() { return 1; }
62+
#pragma omp declare variant(SpecialFuncs::method_) \
63+
match(implementation = {vendor(llvm)})
64+
int Method();
65+
} s;
66+
67+
int SpecialFuncs::Method() { return 1; }
68+
69+
struct SpecSpecialFuncs {
70+
void vd() {}
71+
SpecSpecialFuncs();
72+
~SpecSpecialFuncs();
73+
74+
int method_();
75+
#pragma omp declare variant(SpecSpecialFuncs::method_) \
76+
match(implementation = {vendor(llvm)})
77+
int method() { return 1; }
78+
#pragma omp declare variant(SpecSpecialFuncs::method_) \
79+
match(implementation = {vendor(llvm)})
80+
int Method();
81+
} s1;
82+
83+
int SpecSpecialFuncs::method_() { return 7; }
84+
int SpecSpecialFuncs::Method() { return 1; }
85+
86+
void xxx() {
87+
(void)s.method();
88+
(void)s1.method();
89+
}
90+
91+
#endif // HEADER

0 commit comments

Comments
 (0)