r373387 - [OPENMP50]Initial codegen for declare variant implementation vendor.
Alexey Bataev via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 1 13:18:33 PDT 2019
Author: abataev
Date: Tue Oct 1 13:18:32 2019
New Revision: 373387
URL: http://llvm.org/viewvc/llvm-project?rev=373387&view=rev
Log:
[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.
Added:
cfe/trunk/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp
Modified:
cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=373387&r1=373386&r2=373387&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp Tue Oct 1 13:18:32 2019
@@ -1264,6 +1264,51 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGen
loadOffloadInfoMetadata();
}
+static bool tryEmitAlias(CodeGenModule &CGM, const GlobalDecl &NewGD,
+ const GlobalDecl &OldGD, llvm::GlobalValue *OrigAddr,
+ bool IsForDefinition) {
+ // Emit at least a definition for the aliasee if the the address of the
+ // original function is requested.
+ if (IsForDefinition || OrigAddr)
+ (void)CGM.GetAddrOfGlobal(NewGD);
+ StringRef NewMangledName = CGM.getMangledName(NewGD);
+ llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName);
+ if (Addr && !Addr->isDeclaration()) {
+ const auto *D = cast<FunctionDecl>(OldGD.getDecl());
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(OldGD);
+ llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI);
+
+ // Create a reference to the named value. This ensures that it is emitted
+ // if a deferred decl.
+ llvm::GlobalValue::LinkageTypes LT = CGM.getFunctionLinkage(OldGD);
+
+ // Create the new alias itself, but don't set a name yet.
+ auto *GA =
+ llvm::GlobalAlias::create(DeclTy, 0, LT, "", Addr, &CGM.getModule());
+
+ if (OrigAddr) {
+ assert(OrigAddr->isDeclaration() && "Expected declaration");
+
+ GA->takeName(OrigAddr);
+ OrigAddr->replaceAllUsesWith(
+ llvm::ConstantExpr::getBitCast(GA, OrigAddr->getType()));
+ OrigAddr->eraseFromParent();
+ } else {
+ GA->setName(CGM.getMangledName(OldGD));
+ }
+
+ // Set attributes which are particular to an alias; this is a
+ // specialization of the attributes which may be set on a global function.
+ if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() ||
+ D->isWeakImported())
+ GA->setLinkage(llvm::Function::WeakAnyLinkage);
+
+ CGM.SetCommonAttributes(OldGD, GA);
+ return true;
+ }
+ return false;
+}
+
void CGOpenMPRuntime::clear() {
InternalVars.clear();
// Clean non-target variable declarations possibly used only in debug info.
@@ -1277,6 +1322,14 @@ void CGOpenMPRuntime::clear() {
continue;
GV->eraseFromParent();
}
+ // Emit aliases for the deferred aliasees.
+ for (const auto &Pair : DeferredVariantFunction) {
+ StringRef MangledName = CGM.getMangledName(Pair.second.second);
+ llvm::GlobalValue *Addr = CGM.GetGlobalValue(MangledName);
+ // If not able to emit alias, just emit original declaration.
+ (void)tryEmitAlias(CGM, Pair.second.first, Pair.second.second, Addr,
+ /*IsForDefinition=*/false);
+ }
}
std::string CGOpenMPRuntime::getName(ArrayRef<StringRef> Parts) const {
@@ -11086,6 +11139,80 @@ Address CGOpenMPRuntime::getAddressOfLoc
return Address(Addr, Align);
}
+/// Checks current context and returns true if it matches the context selector.
+template <OMPDeclareVariantAttr::CtxSelectorSetType CtxSet,
+ OMPDeclareVariantAttr::CtxSelectorType Ctx>
+static bool checkContext(const OMPDeclareVariantAttr *A) {
+ assert(CtxSet != OMPDeclareVariantAttr::CtxSetUnknown &&
+ Ctx != OMPDeclareVariantAttr::CtxUnknown &&
+ "Unknown context selector or context selector set.");
+ return false;
+}
+
+/// Checks for implementation={vendor(<vendor>)} context selector.
+/// \returns true iff <vendor>="llvm", false otherwise.
+template <>
+bool checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
+ OMPDeclareVariantAttr::CtxVendor>(
+ const OMPDeclareVariantAttr *A) {
+ return !A->getImplVendor().compare("llvm");
+}
+
+/// Finds the variant function that matches current context with its context
+/// selector.
+static const FunctionDecl *getDeclareVariantFunction(const FunctionDecl *FD) {
+ if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
+ return FD;
+ // Iterate through all DeclareVariant attributes and check context selectors.
+ SmallVector<const OMPDeclareVariantAttr *, 4> MatchingAttributes;
+ for (const auto * A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
+ switch (A->getCtxSelectorSet()) {
+ case OMPDeclareVariantAttr::CtxSetImplementation:
+ switch (A->getCtxSelector()) {
+ case OMPDeclareVariantAttr::CtxVendor:
+ if (checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
+ OMPDeclareVariantAttr::CtxVendor>(A))
+ MatchingAttributes.push_back(A);
+ break;
+ case OMPDeclareVariantAttr::CtxUnknown:
+ llvm_unreachable(
+ "Unknown context selector in implementation selctor set.");
+ }
+ break;
+ case OMPDeclareVariantAttr::CtxSetUnknown:
+ llvm_unreachable("Unknown context selector set.");
+ }
+ }
+ if (MatchingAttributes.empty())
+ return FD;
+ // TODO: implement score analysis of multiple context selectors.
+ const OMPDeclareVariantAttr *MainAttr = MatchingAttributes.front();
+ return cast<FunctionDecl>(
+ cast<DeclRefExpr>(MainAttr->getVariantFuncRef()->IgnoreParenImpCasts())
+ ->getDecl());
+}
+
+bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
+ const auto *D = cast<FunctionDecl>(GD.getDecl());
+ // If the original function is defined already, use its definition.
+ StringRef MangledName = CGM.getMangledName(GD);
+ llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName);
+ if (Orig && !Orig->isDeclaration())
+ return false;
+ const FunctionDecl *NewFD = getDeclareVariantFunction(D);
+ // Emit original function if it does not have declare variant attribute or the
+ // context does not match.
+ if (NewFD == D)
+ return false;
+ GlobalDecl NewGD = GD.getWithDecl(NewFD);
+ if (tryEmitAlias(CGM, NewGD, GD, Orig, IsForDefinition)) {
+ DeferredVariantFunction.erase(D);
+ return true;
+ }
+ DeferredVariantFunction.insert(std::make_pair(D, std::make_pair(NewGD, GD)));
+ return true;
+}
+
llvm::Function *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h?rev=373387&r1=373386&r2=373387&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h (original)
+++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h Tue Oct 1 13:18:32 2019
@@ -644,6 +644,12 @@ private:
/// must be emitted.
llvm::SmallDenseSet<const VarDecl *> DeferredGlobalVariables;
+ /// Mapping of the original functions to their variants and original global
+ /// decl.
+ llvm::MapVector<CanonicalDeclPtr<const FunctionDecl>,
+ std::pair<GlobalDecl, GlobalDecl>>
+ DeferredVariantFunction;
+
/// Flag for keeping track of weather a requires unified_shared_memory
/// directive is present.
bool HasRequiresUnifiedSharedMemory = false;
@@ -1652,6 +1658,9 @@ public:
/// Return whether the unified_shared_memory has been specified.
bool hasRequiresUnifiedSharedMemory() const;
+
+ /// Emits the definition of the declare variant function.
+ virtual bool emitDeclareVariant(GlobalDecl GD, bool IsForDefinition);
};
/// Class supports emissionof SIMD-only code.
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=373387&r1=373386&r2=373387&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Oct 1 13:18:32 2019
@@ -2532,6 +2532,11 @@ void CodeGenModule::EmitGlobal(GlobalDec
return;
}
+ // Check if this must be emitted as declare variant.
+ if (LangOpts.OpenMP && isa<FunctionDecl>(Global) && OpenMPRuntime &&
+ OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/false))
+ return;
+
// If we're deferring emission of a C++ variable with an
// initializer, remember the order in which it appeared in the file.
if (getLangOpts().CPlusPlus && isa<VarDecl>(Global) &&
@@ -3051,6 +3056,10 @@ llvm::Constant *CodeGenModule::GetOrCrea
EmitGlobal(GDDef);
}
}
+ // Check if this must be emitted as declare variant and emit reference to
+ // the the declare variant function.
+ if (LangOpts.OpenMP && OpenMPRuntime)
+ (void)OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true);
if (FD->isMultiVersion()) {
const auto *TA = FD->getAttr<TargetAttr>();
@@ -4327,6 +4336,11 @@ void CodeGenModule::HandleCXXStaticMembe
void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
llvm::GlobalValue *GV) {
+ // Check if this must be emitted as declare variant.
+ if (LangOpts.OpenMP && OpenMPRuntime &&
+ OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true))
+ return;
+
const auto *D = cast<FunctionDecl>(GD.getDecl());
// Compute the function info and LLVM type.
Added: cfe/trunk/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp?rev=373387&view=auto
==============================================================================
--- cfe/trunk/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp (added)
+++ cfe/trunk/test/OpenMP/declare_variant_implementation_vendor_codegen.cpp Tue Oct 1 13:18:32 2019
@@ -0,0 +1,91 @@
+// 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
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple %itanium_abi_triple -fexceptions -fcxx-exceptions -emit-pch -o %t -fopenmp-version=50 %s
+// 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
+// expected-no-diagnostics
+
+// CHECK-NOT: ret i32 {{1|4}}
+// CHECK-DAG: @_Z3barv = {{.*}}alias i32 (), i32 ()* @_Z3foov
+// CHECK-DAG: @_ZN16SpecSpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev
+// CHECK-DAG: @_ZN16SpecSpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecSpecialFuncs*), i32 (%struct.SpecSpecialFuncs*)* @_ZN16SpecSpecialFuncs7method_Ev
+// CHECK-DAG: @_ZN12SpecialFuncs6methodEv = linkonce_odr {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev
+// CHECK-DAG: @_Z4callv = {{.*}}alias i32 (), i32 ()* @_Z4testv
+// CHECK-DAG: @_ZL9stat_usedv = internal alias i32 (), i32 ()* @_ZL10stat_used_v
+// CHECK-DAG: @_ZN12SpecialFuncs6MethodEv = {{.*}}alias i32 (%struct.SpecialFuncs*), i32 (%struct.SpecialFuncs*)* @_ZN12SpecialFuncs7method_Ev
+// CHECK-DAG: declare {{.*}}i32 @_Z5bazzzv()
+// CHECK-DAG: declare {{.*}}i32 @_Z3bazv()
+// CHECK-DAG: ret i32 2
+// CHECK-DAG: ret i32 3
+// CHECK-DAG: ret i32 5
+// CHECK-DAG: ret i32 6
+// CHECK-DAG: ret i32 7
+// CHECK-NOT: ret i32 {{1|4}}
+
+#ifndef HEADER
+#define HEADER
+
+int foo() { return 2; }
+
+#pragma omp declare variant(foo) match(implementation = {vendor(llvm)})
+int bar() { return 1; }
+
+int bazzz();
+#pragma omp declare variant(bazzz) match(implementation = {vendor(llvm)})
+int baz() { return 1; }
+
+int test();
+#pragma omp declare variant(test) match(implementation = {vendor(llvm)})
+int call() { return 1; }
+
+static int stat_unused_();
+#pragma omp declare variant(stat_unused_) match(implementation = {vendor(llvm)})
+static int stat_unused() { return 1; }
+
+static int stat_used_();
+#pragma omp declare variant(stat_used_) match(implementation = {vendor(llvm)})
+static int stat_used() { return 1; }
+
+int main() { return bar() + baz() + call() + stat_used(); }
+
+int test() { return 3; }
+static int stat_unused_() { return 4; }
+static int stat_used_() { return 5; }
+
+struct SpecialFuncs {
+ void vd() {}
+ SpecialFuncs();
+ ~SpecialFuncs();
+
+ int method_() { return 6; }
+#pragma omp declare variant(SpecialFuncs::method_) \
+ match(implementation = {vendor(llvm)})
+ int method() { return 1; }
+#pragma omp declare variant(SpecialFuncs::method_) \
+ match(implementation = {vendor(llvm)})
+ int Method();
+} s;
+
+int SpecialFuncs::Method() { return 1; }
+
+struct SpecSpecialFuncs {
+ void vd() {}
+ SpecSpecialFuncs();
+ ~SpecSpecialFuncs();
+
+ int method_();
+#pragma omp declare variant(SpecSpecialFuncs::method_) \
+ match(implementation = {vendor(llvm)})
+ int method() { return 1; }
+#pragma omp declare variant(SpecSpecialFuncs::method_) \
+ match(implementation = {vendor(llvm)})
+ int Method();
+} s1;
+
+int SpecSpecialFuncs::method_() { return 7; }
+int SpecSpecialFuncs::Method() { return 1; }
+
+void xxx() {
+ (void)s.method();
+ (void)s1.method();
+}
+
+#endif // HEADER
More information about the cfe-commits
mailing list